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
猜你喜欢
- ImageCacheconst int _kDefaultSize = 1000;const int _kDefaultSizeBytes
- 本文是vhr系列的第十二篇,项目地址 https://github.com/lenve/vhr邮件发送也是一个老生常谈的问题了,代码虽然简单
- 相信对于一名JAVA开发者开说properties文件一定再熟悉不过了,比如一下配置:config.properties会经常存放一些系统常
- 详解HDFS多文件Join操作的实例最近在做HDFS文件处理之时,遇到了多文件Join操作,其中包括:All Join以及常用的Left J
- 简介JSR-303 是 JAVA EE 6 中的一项子规范,叫做 Bean Validation。在任何时候,当你要处理一个应用程序的业务逻
- 背景java程序员一般写的是后端服务是JavaWeb类型的项目,主要包括Http接口和dubbo接口,Http接口一般采用的rest风格,那
- Java处理JSON数据有三个比较流行的类库FastJSON、Gson和Jackson。JacksonJackson是由其社区进行维护,简单
- 实现Runnable 接口比继承Thread 类的方式更好:(1)可以避免由于Java单继承带来的局限性;(2)可以实现业务执行逻辑和数据资
- 目录前言简单示例基础操作定时取消关联取消判断取消源码探究构造入手小插曲WaitHandle注册操作取消操作Cancel操作CancelAft
- 本文实例为大家分享了flutter实现appbar下选项卡切换的具体代码,供大家参考,具体内容如下TabBar 、Tab、TabBarVie
- 概述java中的序列化可能大家像我一样都停留在实现Serializable接口上,对于它里面的一些核心机制没有深入了解过。直到最近在项目中踩
- 一、问题描述在使用idea Jrebel续期的时候,修改idea激活服务器地址时,遇到报错:Cannot reactivate, offli
- Remote Debug 综述当我们的后台项目部署到服务器上时,由于环境和本地不同,有时候也会有一些奇奇怪怪的问题出现。只依赖服务器上的日志
- MyBatis框架提供了二级缓存接口,我们只需要实现它再开启配置就可以使用了。特别注意,我们要解决缓存穿透、缓存穿透和缓存雪崩的问题,同时也
- 每种编程语言都有自己操作内存中元素的方式,例如在 C 和 C++ 里是通过指针,而在 Java 中则是通过“引用”。在 JDK.1.2 之后
- 1、首先看一下下面两个sql语句的区别:<select id="selectByNameAndPassword"
- 在java里, 我们可以使用Executors.newFixedThreadPool 来创建线程池, 然后就可以不停的创建新任务,并用线程池
- Commons Beanutils是Apache开源组
- Maven 作为一个优秀的项目管理工具,其插件机制为其功能扩展提供了非常大的便捷性。虽然说大多数情况下,我们可能不太会自己去编写 Maven
- 1. strlen —— 求字符串长度1.1 strlen 的声明与用处strlen ,我们有一些英