在 C 中处理转义序列#

Handle escape sequences in C#

提问人:s_v 提问时间:7/11/2023 最后编辑:s_v 更新时间:7/11/2023 访问量:243

问:

我有一个将 rawText 作为字符串输入的 C# 端点。 输入是在将 a 转换为使用第三方库后发送的,发送的输入格式如下,例如 -filestringaspose

{rawText = "\u0007\u0007\r\r\r\r\r\u0007Random Name\rRandom Address; Overland Park, KS 12345; Cell: 000-000-0000 Email: [email protected]"}

我知道字符串是用 C# 编码的 UTF16,所以当它到达端点时,它会转换为 -

requestobj.RawText = "\a\a\r\r\r\r\r\aRandom Name\r10504 Random Address; Overland Park, KS 12345; Cell: 000-000-0000 Email: [email protected]"

我的推理是否正确,这是由于 C# 字符串是 utf16 编码的?以及删除字符串开头的最佳方法是什么。我正在将此文本传递给另一个第三方 api,该 api 不会返回带有此预置额外文本的正确结果。\a\a\r\r\r\r\r\a

我尝试在下面使用,但我想要一个更通用的解决方案来处理等所有可能性。\n\r\a

var newText = Regex.Replace(inputValue, @"\\a", "");
inputValue = inputValue.Replace(@"\a", "").Replace(@"\r", "");
C# .NET 正则表达式 转义

评论

0赞 Panagiotis Kanavos 7/11/2023
这个问题与编码或Unicode无关。您询问的是用于表示难以在源代码或调试器输出中键入的字符的转义序列。转义序列不存在于编译器生成的实际字符串中,也不存在于调试器显示的实际字符串中。它们也没有什么特别之处,每个字符都可以使用转义序列来表示。您显示的那些用于许多编程语言和操作系统。
1赞 Panagiotis Kanavos 7/11/2023
您显示的文本不会转换为任何内容。调试器使用不同的转义序列显示完全相同的字符串。它显示的不是 Alert 字符的长格式,而是短格式。两者都表示相同的字符和相同的字节。\u0007\a
0赞 s_v 7/11/2023
@PanagiotisKanavos谢谢。我通过添加这个来解决它 - '''Regex.Replace(inputValue, @“[^\u0000-\u007F]”, String.Empty);'''
0赞 Panagiotis Kanavos 7/11/2023
该范围包括所有英文字符。你检查过结果了吗?
0赞 s_v 7/11/2023
我加了一个^

答:

2赞 Panagiotis Kanavos 7/11/2023 #1

这些是转义序列,而不是 UTF8 编码。编码是指如何将字符转换为字节。转义序列用于输入在源代码中难以键入或不可见的字符。调试器也使用它们来显示此类字符。在问题的情况下,没有任何转换。相同的 BELL 字符 (0x07) 可以表示为 both 或 。调试器选择了较短的版本。\a\u0007

要在开始时仅替换这 3 个字符,您可以使用此正则表达式 。为了避免在正则表达式中对转义序列进行双引号,可以使用不转换为转义字符的逐字字符串。@"^[\r\n\a]+"\

var input="\a\a\r\r\r\r\r\aRandom Name\r10504 Random Address; Overland Park, KS 12345; Cell: 000-000-0000 Email: [email protected]";
var pattern=@"^[\r\n\a]+";
var newText=Regex.Replace(input,pattern,"");

这会产生

Random Name 10504 Random Address; Overland Park, KS 12345; Cell: 000-000-0000 Email: [email protected]

要删除任何位置的字符,请删除起始锚点。^

也可以替换所有控制字符。对于带有 的控制字符,有一个特定的 Unicode 类别。 是控制字符类别的简写。\p{Cc}Cc

var pattern=@"\p{Cc}+";
var newText=Regex.Replace(input,pattern,"");

正如文档所解释的,此类别与任何

控制代码字符,Unicode 值为 U+007F 或范围为 U+0000 到 U+001F 或 U+0080 到 U+009F。由 Unicode 名称“Cc”(其他、控件)表示。

评论

0赞 Palle Due 7/11/2023
在代码中输入 \f 而不是 \p。
0赞 Panagiotis Kanavos 7/11/2023
哎呀,修好了。
0赞 Corey 7/11/2023 #2

正如 Panagiotis 所指出的,字符串中转义码的表示只是视觉表示,不会改变字符串的含义或编码。是的,C#(以及一般的 .NET)使用 Unicode/UTF-16 对内存中的字符串进行编码,但这与您的问题无关,在大多数情况下也不重要。

撇开这一点不谈,你的主要问题似乎是这样的:

在字符串开头删除\a\a\r\r\r\r\r\a的最佳方法是什么。

与大多数此类问题一样,有很多方法可以解决这个问题。正则表达式(正如 Panagiotis 所建议的)当然可以完成这项工作,但它们可能很挑剔,并且通常比更直接的选项慢。有时正则表达式最适合特定问题,但这不一定是其中之一。我不认为您正在寻找最快的解决方案......但探索各种选择并没有什么坏处。

所以这里有一些想法。

如果您希望从字符串的开头删除少量已知字符,那么可以使用字符串方法: .具体来说,接受一组要删除的字符的版本:TrimStart()

string cleanText = inputText.TrimLeft('\a', '\r', '\n');

对于少数已知字符来说,这很好。但是,如果您希望从字符串的开头删除任何控制字符,则可以对它们进行计数并从字符串中跳过许多字符:

// Count control characters at the start of the string:
int count = 0;
for (; count < inputText.Length && Char.IsControl(inputText, count); count++)
{ }

// This monster is safe:
string cleanText = 
    count == 0 ? inputText : 
    count >= inputText.Length ? string.Empty :
    inputText[count..];

这恰好是完成该特定工作的最快方法之一,但它不是最漂亮的。除非你经常这样做,否则你可能不会每次都错过额外的几毫秒。

由于性能不是一个关键问题,让我向您介绍一个最慢的选项:LINQ。

string cleanText = new string(inputText.SkipWhile(c => char.IsControl(c)).ToArray());

虽然坦率地说,它的性能很糟糕,但它比高性能版本更具可读性。 在满足条件时跳过项目,其余字符被收集到一个数组中并用于创建新字符串。它很漂亮,但很慢。就像我的猫一样。SkipWhile()