Trim().Split 导致 Contains() 出现问题
Trim().Split causes a problem in Contains()
我正在获取一个字符串并先对其进行修整,然后将其拆分并分配给 string[]
。然后,我将数组中的每个元素用于 string.Contains()
或 string.StartsWith()
方法。有趣的是,即使字符串包含元素,Contains()
也不能正常工作。 StartsWith()
的情况也一样。有人知道这个问题吗?
P.S.: 拆分后我修剪了字符串,问题就解决了。
string inputTxt = "tasklist";
string commands = "net, netsh, tasklist";
string[] maliciousConsoleCommands = commands.Trim(' ').Split(',');
for (int i = 0; i < maliciousConsoleCommands.Length; i++) {
if (inputTxt.StartsWith(maliciousConsoleCommands[i])) {
return false;
}
}
//此代码有效,但不知道为什么以前的代码无效。
string[] maliciousConsoleCommands = commands.Split(',');
for (int i = 0; i < maliciousConsoleCommands.Length; i++) {
if (inputTxt.StartsWith(maliciousConsoleCommands[i].Trim(' '))) {
return false;
}
}
本以为可以正常使用,结果通过拆分后修剪解决了。
看来,你应该 Trim
每个 item :
// ["net", "netsh, "tasklist"]
string[] maliciousConsoleCommands = commands
.Split(',') // "net" " netsh", " tasklist" - note leading spaces
.Select(item => item.Trim()) // removing leading spaces from each item
.ToArray();
最后,如果你想测试inputTxt
是否是恶意的:
if (commands
.Split(',')
.Select(item => item.Trim()) // You can combine Select and Any
.Any(item => inputTxt.StartsWith(item))
return false;
你的分隔符不是逗号字符,它是一个逗号后跟一个白色-space - 所以不要用 ','
分割,只需用 ", "
:[=13 分割=]
string[] maliciousConsoleCommands = commands.Split(new string[] {", "});
这将 return 没有前导的项目 space 因此 trim 将是多余的。
您提供的第一个代码将不起作用,因为您想要 trim 初始字符串,因此 "net, netsh, tasklist"
在 trim 之后将保持不变(没有前导和尾随 spaces),然后用逗号将其拆分将生成具有前导 space 的条目。因此,您会得到意想不到的结果。您应该 trimming after 拆分字符串。
第二个代码也不起作用,因为您在 StartsWith
之后使用 Trim
,其中 return bool
值。您不能将 Trim
应用于 bool
,此代码甚至不应该编译。
如果命令本身没有空格,另一种拆分方法是使用 ' '
本身作为分隔符,并丢弃空条目:
var maliciousConsoleCommands = commands.Split(new[]{',',' '},StringSplitOptions.RemoveEmptyEntries)
.ToArray();
这避免了每个字符串操作命令生成的临时字符串。
为了让您的代码正常工作,您需要为每个命令使用 Contains
,而不是使用 StartWith
:
var isSuspicious = maliciousCommands.Any(cmd=>input.Contains(cmd));
甚至:
var isSuspicious = maliciousCommands.Any(input.Contains);
如果您有多个命令,或者输入文本很大,这可能会变得相当慢
正则表达式替代
一种更快的技术是使用正则表达式。这比搜索单个关键字执行速度 很多 :
var regex=new Regex("net|netsh|tasklist");
var isSuspicious=regex.IsMatch(inputTxt);
正则表达式是线程安全的,这意味着它们可以被创建一次并被不同的人重复使用 threads/requests。
通过使用 Match/Matches
而不是 IsMatch
,正则表达式可以 return 检测到的实际关键字:
var detection=regex.Match(inputTxt);
if (detection.Success)
{
var detectedKeyword=detection.Value;
....
}
将原始逗号分隔列表转换为正则表达式可以使用单个 String.Replace(", ")
或另一个可以处理任何空白字符的正则表达式来执行:
string commands = "net , netsh, \ttasklist";
var pattern=Regex.Replace(commands,@"\s*,\s*","|").Dump();
var regex=new Regex(pattern);
只检测整个单词
Contains
和原始正则表达式都匹配 tasklist1
和 tasklist
。如果模式被单词定界符包围,则可以只匹配整个单词,\b
:
@"\b(" + pattern + @")\b"
这将匹配 tasklist
和 net
但拒绝 tasklist1
我正在获取一个字符串并先对其进行修整,然后将其拆分并分配给 string[]
。然后,我将数组中的每个元素用于 string.Contains()
或 string.StartsWith()
方法。有趣的是,即使字符串包含元素,Contains()
也不能正常工作。 StartsWith()
的情况也一样。有人知道这个问题吗?
P.S.: 拆分后我修剪了字符串,问题就解决了。
string inputTxt = "tasklist";
string commands = "net, netsh, tasklist";
string[] maliciousConsoleCommands = commands.Trim(' ').Split(',');
for (int i = 0; i < maliciousConsoleCommands.Length; i++) {
if (inputTxt.StartsWith(maliciousConsoleCommands[i])) {
return false;
}
}
//此代码有效,但不知道为什么以前的代码无效。
string[] maliciousConsoleCommands = commands.Split(',');
for (int i = 0; i < maliciousConsoleCommands.Length; i++) {
if (inputTxt.StartsWith(maliciousConsoleCommands[i].Trim(' '))) {
return false;
}
}
本以为可以正常使用,结果通过拆分后修剪解决了。
看来,你应该 Trim
每个 item :
// ["net", "netsh, "tasklist"]
string[] maliciousConsoleCommands = commands
.Split(',') // "net" " netsh", " tasklist" - note leading spaces
.Select(item => item.Trim()) // removing leading spaces from each item
.ToArray();
最后,如果你想测试inputTxt
是否是恶意的:
if (commands
.Split(',')
.Select(item => item.Trim()) // You can combine Select and Any
.Any(item => inputTxt.StartsWith(item))
return false;
你的分隔符不是逗号字符,它是一个逗号后跟一个白色-space - 所以不要用 ','
分割,只需用 ", "
:[=13 分割=]
string[] maliciousConsoleCommands = commands.Split(new string[] {", "});
这将 return 没有前导的项目 space 因此 trim 将是多余的。
您提供的第一个代码将不起作用,因为您想要 trim 初始字符串,因此 "net, netsh, tasklist"
在 trim 之后将保持不变(没有前导和尾随 spaces),然后用逗号将其拆分将生成具有前导 space 的条目。因此,您会得到意想不到的结果。您应该 trimming after 拆分字符串。
第二个代码也不起作用,因为您在 StartsWith
之后使用 Trim
,其中 return bool
值。您不能将 Trim
应用于 bool
,此代码甚至不应该编译。
如果命令本身没有空格,另一种拆分方法是使用 ' '
本身作为分隔符,并丢弃空条目:
var maliciousConsoleCommands = commands.Split(new[]{',',' '},StringSplitOptions.RemoveEmptyEntries)
.ToArray();
这避免了每个字符串操作命令生成的临时字符串。
为了让您的代码正常工作,您需要为每个命令使用 Contains
,而不是使用 StartWith
:
var isSuspicious = maliciousCommands.Any(cmd=>input.Contains(cmd));
甚至:
var isSuspicious = maliciousCommands.Any(input.Contains);
如果您有多个命令,或者输入文本很大,这可能会变得相当慢
正则表达式替代
一种更快的技术是使用正则表达式。这比搜索单个关键字执行速度 很多 :
var regex=new Regex("net|netsh|tasklist");
var isSuspicious=regex.IsMatch(inputTxt);
正则表达式是线程安全的,这意味着它们可以被创建一次并被不同的人重复使用 threads/requests。
通过使用 Match/Matches
而不是 IsMatch
,正则表达式可以 return 检测到的实际关键字:
var detection=regex.Match(inputTxt);
if (detection.Success)
{
var detectedKeyword=detection.Value;
....
}
将原始逗号分隔列表转换为正则表达式可以使用单个 String.Replace(", ")
或另一个可以处理任何空白字符的正则表达式来执行:
string commands = "net , netsh, \ttasklist";
var pattern=Regex.Replace(commands,@"\s*,\s*","|").Dump();
var regex=new Regex(pattern);
只检测整个单词
Contains
和原始正则表达式都匹配 tasklist1
和 tasklist
。如果模式被单词定界符包围,则可以只匹配整个单词,\b
:
@"\b(" + pattern + @")\b"
这将匹配 tasklist
和 net
但拒绝 tasklist1