1

使用 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:导致完全相同匹配的模式会导致完全不同的拆分输出。这怎么可能??

4

2 回答 2

2

原因是来自MSDN的这句话:

如果在 Regex.Split 表达式中使用捕获括号,则任何捕获的文本都将包含在结果字符串数组中。

Split如果您真的只想在匹配时拆分字符串,则不应使用捕获组。你可以避免捕获组,通过使用(?:...)代替(...)你拥有的每一个。

另外,正如您正确假设的那样。第一个和最后一个""源于字符串以匹配开始和结束的事实(因此这些匹配之前和之后的空字符串将在拆分中报告)。

这是一个更适合您目的的正则表达式:

@"(?:^|\s+)#\w*[A-Za-z_]+\w*"

请注意,拥有+第一个子模式的外部也是不必要的,并且会导致尴尬的副作用。首先,它允许该组多次捕获(这就是为什么你有两个加法"""":一个 for^和一个 for \s)。其次,在第一个空格字符匹配后不需要重复^,所以只重复空格字符就足够了。此外,根本不需要对单词进行分组#

但是,如果您只想匹配#name位于字符串开头或前面有空格的内容(即不是* 前面有 ** 非空格字符),为什么要在匹配中包含可能的空格。消极的向后看给你一个很好的出路:

@"(?<!\S)#\w*[A-Za-z_]+\w*"

这正是上面描述的。如果(?<!\S)没有剩余非空格字符,则匹配(如果有,则在匹配中不包括空格字符)。这涵盖了两种情况,无需交替,不需要Trim键名。

于 2012-11-27T17:52:11.260 回答
0

因为您要拆分的正则表达式匹配 1 个或多个空格,后跟一个哈希 ('#'),后跟 1 个或多个单词字符。

任何匹配但未包含在结果中的内容。

有两种方法可以做到这一点:

  1. 拆分不需要的内容并过滤结果。
  2. 积极地只寻找想要的东西。

这是具有上述两个选项的一些代码:

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();
于 2012-11-27T18:03:14.463 回答