使用RegEx时遇到一种奇怪的行为。
dataString = "#Name #Location New York #Rating"
string[] rawValues = Regex.Split(dataString.Trim(), "(^|\\s)+#\\w+");
模式匹配:"#Name", " #Location", " #Rating"
(这是我打算匹配的)
拆分返回:["", "", "", " ", "New York", " ", ""]
问题#1:cunfusion已经在这里开始了。为什么位置0,1,2
上有空字符串?两个匹配,一个因为它位于字符串的第一个位置?
但这不是奇怪的部分。
string[] rawValues = Regex.Split(dataString.Trim(), "(\\s|^)+#(\\w*[A-Za-z_]+\\w*)");
模式匹配:"#Name", " #Location", " #Rating"
(与之前相同)
但是分裂返回:["", "", "Name", "", " ", "Location"," New York", " ", "Rating",""]
问题#2:导致完全相同匹配的模式导致完全不同的分割输出。这怎么可能?
答案 0 :(得分:2)
原因是这句话来自MSDN:
如果在Regex.Split表达式中使用捕获括号,则任何捕获的文本都包含在结果字符串数组中。
如果您真的只想在匹配时拆分字符串,则不应在Split
中使用捕获组。您可以使用(?:...)
代替您拥有的每个(...)
来避免捕获群组。
另外,正如你所正确的那样。第一个和最后一个""
源于字符串以匹配开始和结束的事实(因此在分割中将报告这些匹配之前和之后的空字符串)。
这是一个更适合您的正则表达式:
@"(?:^|\s+)#\w*[A-Za-z_]+\w*"
请注意,在第一个子模式之外使用+
也是不必要的,并导致尴尬的副作用。首先,它允许群组多次捕获(这就是为什么你有两个""
,""
:一个用于^
,一个用于\s
)。其次,在第一个空格字符匹配后不需要重复^
,因此仅重复空格字符就足够了。此外,根本不需要在#
之后对单词进行分组。
但是,如果你想要的是匹配#name
之类的东西,当它位于字符串的开头或者前面有一个空格(即 not *前面是**非空格1}强>字符),为什么在匹配中包含可能的空格。消极的外观为你提供了一个很好的出路:
@"(?<!\S)#\w*[A-Za-z_]+\w*"
这完全如上所述。 (?<!\S)
匹配,如果没有剩余非空格字符(如果有匹配则不包括匹配中的空格字符)。这涵盖了两种情况,没有交替,和您不需要Trim
您的密钥名称。
答案 1 :(得分:0)
因为您要拆分的正则表达式匹配1个或更多空格,后跟哈希('#')后跟1个或多个单词字符。
任何匹配的内容都不会包含在结果中。
有两种方法可以做到这一点:
这里有一些代码包含上述两个选项:
static void Main( string[] args )
{
string sourceText = "#Name #Location New York #Rating" ;
// option 1: split on whitespace and then toss whatever isn't wanted
string[] hashTokens1 = sourceText.Split().Where( x => x.StartsWith("#") ).ToArray() ;
// option 2: actively search for what is desired
string[] hashTokens2 = ParseSourceData( sourceText ).ToArray() ;
return ;
}
private static readonly Regex hashTokenPattern = new Regex( @"#\w+");
private static IEnumerable<string> ParseSourceData( string s )
{
for ( Match m = hashTokenPattern.Match( s ) ; m.Success ; m = m.NextMatch() )
{
yield return m.Value ;
}
}
我自己,我会使用第二个选项,因为它更能说明你想要完成的事情。一个好的一般规则是倾向于积极断言或测试而不是消极。
您还可以将第二个选项写为“单行,因此:
// option 2: actively search for what is desired
Regex hashTokenPattern = new Regex( @"#\w+");
string[] hashTokens2 = hashTokenPattern.Matches(sourceText).Cast<Match>().Select(x=>x.Value).ToArray();