背景
最近發現某個資料採集的系統拿下來的資料,有些欄位的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();
搞定。