我想从字符串中删除所有特殊字符。允许输入A-Z(大写或小写)、数字(0-9)、下划线(_)或点符号(.)。
我有以下,它是有效的,但我怀疑(我知道!)它不是很有效:
public static string RemoveSpecialCharacters(string str)
{
StringBuilder sb = new StringBuilder();
for (int i = 0; i < str.Length; i++)
{
if ((str[i] >= '0' && str[i] <= '9')
|| (str[i] >= 'A' && str[i] <= 'z'
|| (str[i] == '.' || str[i] == '_')))
{
sb.Append(str[i]);
}
}
return sb.ToString();
}
最有效的方法是什么?正则表达式是什么样子的,它与普通字符串操作相比如何?
要清洗的字符串相当短,长度通常在10到30个字符之间。
如果你使用的是动态字符列表,LINQ可以提供一个更快更优雅的解决方案:
public static string RemoveSpecialCharacters(string value, char[] specialCharacters)
{
return new String(value.Except(specialCharacters).ToArray());
}
我将这种方法与之前的两种“快速”方法(发行版编译)进行了比较:
字符数组解决方案由LukeH - 427毫秒
StringBuilder解决方案- 429毫秒
LINQ(这个答案)- 98毫秒
注意,算法略有修改-字符作为数组传入,而不是硬编码,这可能会有轻微的影响(即/其他解决方案将有一个内部for循环来检查字符数组)。
如果我使用LINQ where子句切换到硬编码的解决方案,结果是:
字符数组解决方案- 7ms
StringBuilder解决方案- 22ms
LINQ - 60毫秒
如果您计划编写一个更通用的解决方案,而不是硬编码字符列表,那么可能值得考虑LINQ或经过修改的方法。LINQ绝对能给你简洁、高可读性的代码——甚至比Regex更好。
下面的代码有以下输出(结论是,我们也可以节省一些内存资源分配数组更小的大小):
lookup = new bool[123];
for (var c = '0'; c <= '9'; c++)
{
lookup[c] = true; System.Diagnostics.Debug.WriteLine((int)c + ": " + (char)c);
}
for (var c = 'A'; c <= 'Z'; c++)
{
lookup[c] = true; System.Diagnostics.Debug.WriteLine((int)c + ": " + (char)c);
}
for (var c = 'a'; c <= 'z'; c++)
{
lookup[c] = true; System.Diagnostics.Debug.WriteLine((int)c + ": " + (char)c);
}
48: 0
49: 1
50: 2
51: 3
52: 4
53: 5
54: 6
55: 7
56: 8
57: 9
65: A
66: B
67: C
68: D
69: E
70: F
71: G
72: H
73: I
74: J
75: K
76: L
77: M
78: N
79: O
80: P
81: Q
82: R
83: S
84: T
85: U
86: V
87: W
88: X
89: Y
90: Z
97: a
98: b
99: c
100: d
101: e
102: f
103: g
104: h
105: i
106: j
107: k
108: l
109: m
110: n
111: o
112: p
113: q
114: r
115: s
116: t
117: u
118: v
119: w
120: x
121: y
122: z
你也可以添加以下代码行来支持俄语区域设置(数组大小为1104):
for (var c = 'А'; c <= 'Я'; c++)
{
lookup[c] = true; System.Diagnostics.Debug.WriteLine((int)c + ": " + (char)c);
}
for (var c = 'а'; c <= 'я'; c++)
{
lookup[c] = true; System.Diagnostics.Debug.WriteLine((int)c + ": " + (char)c);
}
另一种试图通过减少分配来提高性能的方法,特别是在多次调用此函数的情况下。
它之所以有效,是因为可以保证结果不会比输入长,因此可以在不在内存中创建额外副本的情况下传递输入和输出。因此,您不能使用stackalloc来创建缓冲区数组,因为这需要从缓冲区中复制一个副本。
public static string RemoveSpecialCharacters(this string str)
{
return RemoveSpecialCharacters(str.AsSpan()).ToString();
}
public static ReadOnlySpan<char> RemoveSpecialCharacters(this ReadOnlySpan<char> str)
{
Span<char> buffer = new char[str.Length];
int idx = 0;
foreach (char c in str)
{
if (char.IsLetterOrDigit(c))
{
buffer[idx] = c;
idx++;
}
}
return buffer.Slice(0, idx);
}