将非字母数字字形转换为 Unicode,同时保留字母数字



我需要将字符串中的非字母数字字形转换为它们的 unicode 值,同时保留字母数字字符。有没有一种方法可以在 C# 中执行此操作?

例如,我需要转换此字符串:

"hello world!"

对此:

"hello_x0020_world_x0021_"

要使 XML 节点名称的字符串安全,您应该使用 XmlConver.EncodeName。

请注意,如果您需要对所有非字母数字字符进行编码,则需要自己编写,因为该方法未对"_"进行编码。

您可以使用LINQSelect扩展方法从以下代码开始:

string str = "hello world!";
string a = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
a += a.ToLower();
char[] alphabet = a.ToCharArray();
str = string.Join("",
str.Select(ch => alphabet.Contains(ch) ? 
ch.ToString() : String.Format("_x{0:x4}_", ch)).ToArray()
);

现在显然它有一些问题:

  • 它在字符列表中进行线性搜索
  • 错过数字...
  • 如果我们添加数字需要确定第一个字符是否可以成为数字(假设是)
  • 代码创建大量立即丢弃的字符串(每个字符一个)
  • 字母数字仅限于 ASCII(假设正常,如果不是Char.IsLetterOrDigit提供帮助)
  • 对纯字母数字字符串做了很多工作

前两个很简单 - 我们可以使用由完整字符列表初始化的HashSet(O(1)Contains)(如果任何 alpah 数字字符可以使用现有方法 -Char.IsLetterOrDigit更具可读性):

public static HashSet<char> asciiAlphaNum = new HashSet<char>
("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789");

为了避免真正毫无意义地为即时 GC 生成字符串ch.ToString(),我们需要弄清楚如何从charstring的混合中构造字符串。String.Join不起作用,因为它希望字符串开始,常规new string(...)没有混合charstring的选项。所以我们只剩下StringBuilder愉快地将两者带到Append.如果大多数字符串没有其他字符,请考虑从初始大小开始str.Length

因此,对于每个角色,我们只需要builder.Append(ch)builder.AppendFormat(("_x{0:x4}_", (int)ch).要执行迭代,只使用常规foreach更容易,但如果真的想要 LINQ -Enumerable.Aggregate是要走的路。

string ReplaceNonAlphaNum(string str)
{
var builder = new StringBuilder(); 
foreach (var ch in str)
{
if (asciiAlphaNum.Contains(ch))
builder.Append(ch);
else
builder.AppendFormat("_x{0:x4}_", (int)ch);
}
return builder.ToString();    
}
string ReplaceNonAlphaNumLinq(string str)
{
return str.Aggregate(new StringBuilder(), (builder, ch) => 
asciiAlphaNum.Contains(ch) ? 
builder.Append(ch) : builder.AppendFormat("_x{0:x4}_", (int)ch)           
).ToString();
}

最后一点 - 如果没有什么要转换的,我们真的不需要做任何事情 - 所以一些检查,如检查 c# 中字符串中的字母数字字符将有助于避免额外的字符串。

因此最终版本(LINQ,因为它更短,更花哨):

private static asciiAlphaNumRx = new Regex(@"^[a-zA-Z0-9]*$");
public static HashSet<char> asciiAlphaNum = new HashSet<char>
("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789");
string ReplaceNonAlphaNumLinq(string str)
{
return asciiAlphaNumRx.IsMatch(str) ? str :
str.Aggregate(new StringBuilder(), (builder, ch) => 
asciiAlphaNum.Contains(ch) ? 
builder.Append(ch) : builder.AppendFormat("_x{0:x4}_", (int)ch)            
).ToString();
}

或者,整个事情可以用正则表达式完成 - 请参阅正则表达式替换:使用自定义函数转换模式作为起点。

最新更新