C#移除字符串中的不可见Unicode字符 案例代码
作者:程序设计实验室 发布时间:2023-04-28 19:06:06
C#移除字符串中的不可见Unicode字符
背景
最近发现某个数据采集的系统拿下来的数据,有些字段的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 |
可以看到上面那个 \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();
搞定。
参考资料
UniCode编码表及部分不可见字符过滤方案 - https://www.cnblogs.com/fan-yuan/p/8176886.html
https://stackoverflow.com/questions/6198986/how-can-i-replace-non-printable-unicode-characters-in-java
补充:C# 字符串与unicode互相转换实战案例
代码如下所示:
/// <summary>
/// 字符串转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>
/// 字符串转为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字符串转为正常字符串
/// </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;
}
来源:https://www.cnblogs.com/deali/p/17085516.html


猜你喜欢
- 本文实例讲述了Android实现使用微信登录第三方APP的方法。分享给大家供大家参考,具体如下:使用微信登录APP,免去注册过程,现在已经有
- 摘要:Java8通过Function获取字段名,解决硬编码,效果类似于mybatis-plus的LambdaQueryWrapper。本文总
- 什么是包包 (package) 是组织类的一种方式.使用包的主要目的是保证类的唯一性.例如, 你在代码中写了一个 Test 类. 然后你的同
- IDEA创建一个传统JAVA WEB项目(不使用maven构建)方法一File --> NEW --> Project --&g
- 先给大家展示下效果图,喜欢的朋友可以下载源码哦。完成这个效果的是使用了 IOS_Dialog_Library下载地址:http://xiaz
- ImageCacheconst int _kDefaultSize = 1000;const int _kDefaultSizeBytes
- 日常使用中spring的 @Cacheable 大家一定不陌生,基于aop机制的缓存实现,并且可以选择cacheManager具体提供缓存的
- 一、什么是桥接模式:桥接,顾名思义,就是用来连接两个部分,使得两个部分可以互相通讯,桥接模式的作用就是为被分离的抽象部分和实现部分搭桥。在现
- Java CharArrayReader流一、CharArrayReader流定义API说明:该类实现了一个可用作字符输入流的字符缓冲区,即
- 1 简介AOP,即面向切面编程是很常用的技术,特别是在Java Web开发中。而最流行的AOP框架分别是Spring AOP和AspectJ
- 一、DataSource首先大家要清楚DataSource属于MyBatis三层架构设计的基础层 然后我们来看看具体的实现。在数据持久层中
- 本文实例讲述了Android开发之完成登陆界面的数据保存回显操作。分享给大家供大家参考,具体如下:LoginActivity.java:pa
- 这篇文章主要介绍了SpringBoot文件访问映射如何实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要
- 一、导航栏UINavigationBar1、导航栏的使用在iOS开发中,我们通常会使用导航控制器,导航控制器中封装了一个UINavigati
- 经过一段时间的学习和项目实践,你会发现,打包->上传蒲公英->生成二维码是一个枯燥且乏味的事情,只要打包配置项,配置完成,剩下的
- 解析XML文件:在Android平台上可以使用SAX、DOM和Android附带的pull解析器解析XML文件;pull解析器提供了各种事件
- 在计算机科学中,正则表达式是指一个用来描述或者匹配一系列符合某个句法规则的字符串的单个字符串。在很多文本编辑器或其他工具里,正则表达式通常被
- 在java中常常会遇到这样一个问题,在实际应用中,总会碰到对List排序并过滤重复的问题,如果List中放的只是简单的String类型过滤s
- 每一个应用程序,其实都会有分享的需求,比如一键分享一篇文章或者一些活动到微博或者微信亦或者是twitter等社交平台,因为人类是社交动物,而
- 1.小程序推送信息列如我们去餐厅等位有预约提醒,剩余桌数首先申请一个小程序,微信开放平台:小程序2.申请小程序信息,申请信息模板appid&