C#移除字串中的不可見Unicode字元

程式設計實驗室發表於2023-02-02

背景

最近發現某個資料採集的系統拿下來的資料,有些欄位的JSON被莫名截斷了,導致後續資料分析的時候解析JSON失敗。

類似這樣

{"title": "你好

或者這樣,多了個雙引號啥的

{"title":""你好"}

因為資料庫是Oracle,起初以為是Oracle這老古董出問題了,結果一番折騰,把每條寫入資料的SQL語句都拿出來,看起來裡面的JSON格式都沒問題。

這也太詭異了吧,看起來沒毛病,但就為啥JSON被隨機截斷呢?

最後我試著把整段SQL放在Rider的 query console 裡面執行,然後再去資料庫裡讀取這段JSON,居然發現變成這樣了:

{"title":"?你好"}

啊這,看到這個大大的問號,立刻就能知道這個“你好”裡面不止是這兩個字,肯定含有不可見的Unicode字元。

然後把這段JSON複製出來,用16進位制模式開啟,果然看到在“你好”前面有一個 \u0020 的字元…

Unicode碼錶

  • 0000-007F:C0控制符及基本拉丁文 (C0 Control and Basic Latin)
  • 0080-00FF:C1控制符及拉丁文補充-1 (C1 Control and Latin 1 Supplement)
  • 0100-017F:拉丁文擴充套件-A (Latin Extended-A)
  • 0180-024F:拉丁文擴充套件-B (Latin Extended-B)
  • 0250-02AF:國際音標擴充套件 (IPA Extensions)
  • 02B0-02FF:空白修飾字母 (Spacing Modifiers)
  • ……

這裡再附上部分 Unicode 表格

U+ 0 1 2 3 4 5 6 7 8 9 A B C D E F
0000 NUL SOH STX ETX EOT ENQ ACK BEL BS HT LF VT FF CR SO SI
0010 DLE DC1 DC2 DC3 DC4 NAK SYN ETB CAN EM SUB ESC FS GS RS US
0020 ! " # $ % & ' ( ) * + , - . /
0030 0 1 2 3 4 5 6 7 8 9 : ; < = > ?
0040 @ A B C D E F G H I J K L M N O
0050 P Q R S T U V W X Y Z [ \ ] ^ _
0060 ` a b c d e f g h i j k l m n o

可以看到上面那個 \u0020 在第三行第一列,是一個不可見字元,躲在標題的前面

也就是因為這個 Unicode 字元,Oracle無法正確解析,所以導致了插入資料的時候錯亂了

所以破案了,就是系統前臺使用人員,在輸入的時候不知道咋滴搞了個Unicode字元進去…

解決方法就是我這邊採集的時候再做一次過濾…

沒想到C#要搞個過濾 Unicode 還挺折騰的,資料太少…

最後還是參考了Java的資料搞的。= =...

程式碼

程式碼如下

寫了個擴充套件方法來過濾

public static class StringExt { 
    // 控制字元
    private static readonly Regex ControlCharRegex = new Regex(@"[\p{C}]", RegexOptions.Compiled);

    /// <summary>
    /// 移除控制字元
    /// </summary>
    public static string RemoveControlChars(this string text) {
        return ControlCharRegex.Replace(text, string.Empty);
    }
}

要使用的時候就這樣

var outStr = "帶有Unicode的字串".RemoveControlChars();

搞定。

參考資料

相關文章