C#移除字符串中的不可見(jiàn)Unicode字符 案例代碼
C#移除字符串中的不可見(jiàn)Unicode字符
背景
最近發(fā)現(xiàn)某個(gè)數(shù)據(jù)采集的系統(tǒng)拿下來(lái)的數(shù)據(jù),有些字段的JSON被莫名截?cái)嗔?,?dǎo)致后續(xù)數(shù)據(jù)分析的時(shí)候解析JSON失敗。
類(lèi)似這樣
{"title": "你好
或者這樣,多了個(gè)雙引號(hào)啥的
{"title":""你好"}
因?yàn)閿?shù)據(jù)庫(kù)是Oracle,起初以為是Oracle這老古董出問(wèn)題了,結(jié)果一番折騰,把每條寫(xiě)入數(shù)據(jù)的SQL語(yǔ)句都拿出來(lái),看起來(lái)里面的JSON格式都沒(méi)問(wèn)題。
這也太詭異了吧,看起來(lái)沒(méi)毛病,但就為啥JSON被隨機(jī)截?cái)嗄兀?/p>
最后我試著把整段SQL放在Rider的 query console 里面執(zhí)行,然后再去數(shù)據(jù)庫(kù)里讀取這段JSON,居然發(fā)現(xiàn)變成這樣了:
{"title":"?你好"}
啊這,看到這個(gè)大大的問(wèn)號(hào),立刻就能知道這個(gè)“你好”里面不止是這兩個(gè)字,肯定含有不可見(jiàn)的Unicode字符。
然后把這段JSON復(fù)制出來(lái),用16進(jìn)制模式打開(kāi),果然看到在“你好”前面有一個(gè) \u0020
的字符…
Unicode碼表
- 0000-007F:C0控制符及基本拉丁文 (C0 Control and Basic Latin)
- 0080-00FF:C1控制符及拉丁文補(bǔ)充-1 (C1 Control and Latin 1 Supplement)
- 0100-017F:拉丁文擴(kuò)展-A (Latin Extended-A)
- 0180-024F:拉丁文擴(kuò)展-B (Latin Extended-B)
- 0250-02AF:國(guó)際音標(biāo)擴(kuò)展 (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 |
可以看到上面那個(gè) \u0020
在第三行第一列,是一個(gè)不可見(jiàn)字符,躲在標(biāo)題的前面
也就是因?yàn)檫@個(gè) Unicode 字符,Oracle無(wú)法正確解析,所以導(dǎo)致了插入數(shù)據(jù)的時(shí)候錯(cuò)亂了
所以破案了,就是系統(tǒng)前臺(tái)使用人員,在輸入的時(shí)候不知道咋滴搞了個(gè)Unicode字符進(jìn)去…
解決方法就是我這邊采集的時(shí)候再做一次過(guò)濾…
沒(méi)想到C#要搞個(gè)過(guò)濾 Unicode 還挺折騰的,資料太少…
最后還是參考了Java的資料搞的。= =...
代碼
代碼如下
寫(xiě)了個(gè)擴(kuò)展方法來(lái)過(guò)濾
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); } }
要使用的時(shí)候就這樣
var outStr = "帶有Unicode的字符串".RemoveControlChars();
搞定。
參考資料
UniCode編碼表及部分不可見(jiàn)字符過(guò)濾方案 - https://www.cnblogs.com/fan-yuan/p/8176886.html
補(bǔ)充:C# 字符串與unicode互相轉(zhuǎn)換實(shí)戰(zhàn)案例
代碼如下所示:
/// <summary> /// 字符串轉(zhuǎn)Unicode /// </summary> /// <param name="source">源字符串</param> /// <returns>Unicode編碼后的字符串</returns> public static string String2Unicode(string source) { var bytes = Encoding.Unicode.GetBytes(source); var stringBuilder = new StringBuilder(); for (var i = 0; i < bytes.Length; i += 2) { stringBuilder.AppendFormat("\\u{0:x2}{1:x2}", bytes[i + 1], bytes[i]); } return stringBuilder.ToString(); } /// <summary> /// 字符串轉(zhuǎn)為UniCode碼字符串 /// </summary> /// <param name="s"></param> /// <returns></returns> public static string StringToUnicode(string s) { char[] charbuffers = s.ToCharArray(); byte[] buffer; StringBuilder sb = new StringBuilder(); for (int i = 0; i < charbuffers.Length; i++) { buffer = System.Text.Encoding.Unicode.GetBytes(charbuffers[i].ToString()); sb.Append(String.Format("\\u{0:X2}{1:X2}", buffer[1], buffer[0])); } return sb.ToString(); } /// <summary> /// Unicode字符串轉(zhuǎn)為正常字符串 /// </summary> /// <param name="srcText"></param> /// <returns></returns> public static string UnicodeToString(string srcText) { string dst = ""; string src = srcText; int len = srcText.Length / 6; for (int i = 0; i <= len - 1; i++) { string str = ""; str = src.Substring(0, 6).Substring(2); src = src.Substring(6); byte[] bytes = new byte[2]; bytes[1] = byte.Parse(int.Parse(str.Substring(0, 2), System.Globalization.NumberStyles.HexNumber).ToString()); bytes[0] = byte.Parse(int.Parse(str.Substring(2, 2), System.Globalization.NumberStyles.HexNumber).ToString()); dst += Encoding.Unicode.GetString(bytes); } return dst; }
到此這篇關(guān)于C#移除字符串中的不可見(jiàn)Unicode字符 的文章就介紹到這了,更多相關(guān)C#移除Unicode字符 內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C# 獲取當(dāng)前年份的周期及周期所在日期范圍(推薦)
這篇文章主要介紹了C# 獲取當(dāng)前年份的周期,周期所在日期范圍 ,非常不錯(cuò),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2018-05-05淺談Visual Studio 2019 Vue項(xiàng)目的目錄結(jié)構(gòu)
這篇文章主要介紹了Visual Studio 2019 Vue項(xiàng)目 目錄結(jié)構(gòu),本文通過(guò)圖文并茂的形式給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-03-03WPF利用DrawingContext實(shí)現(xiàn)繪制溫度計(jì)
這篇文章主要為大家詳細(xì)介紹了如何利用WPF和DrawingContext實(shí)現(xiàn)繪制溫度計(jì),文中的示例代碼講解詳細(xì),對(duì)我們學(xué)習(xí)或工作有一定幫助,感興趣的小伙伴可以了解一下2022-09-09Winform開(kāi)發(fā)中使用下拉列表展示字典數(shù)據(jù)的幾種方式
這篇文章介紹了Winform開(kāi)發(fā)中使用下拉列表展示字典數(shù)據(jù)的幾種方式,文中通過(guò)示例代碼介紹的非常詳細(xì)。對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-09-09C#結(jié)合JavaScript實(shí)現(xiàn)多文件上傳功能
在許多應(yīng)用場(chǎng)景里,多文件上傳是一項(xiàng)比較實(shí)用的功能,本文主要為大家詳細(xì)介紹了C#如何結(jié)合JavaScript實(shí)現(xiàn)多文件上傳功能,感興趣的小伙伴可以了解下2023-12-12