空间正则表达式拆分没有引用前瞻性

时间:2013-10-29 17:31:18

标签: c# .net regex

我已经看到很多正则表达式的答案非常接近我所需要的,但它并不完全存在。问题是我有一个字符串,我需要在一个字符上拆分(例如:space或'='),但我想忽略引号内的任何内容(甚至引号内的引号)。

我能得到的最接近的是this

" (?=(?:[^"]*"[^"]*")*[^"]*$)"

哪个效果很好,有两个警告:引号中时间不合适的空格会触发错误的分割,并向后读取。我不关心的第一个问题是,我无能为力,我可以解决它。但第二个是至关重要的。

案例是,有时我正在复兴的字符串可能会在最后意外遗漏一句话。这并没有真正打扰我的系统,但上面的正则表达式向后,所以它打破了一切:

string test = "foo bar \"foo bar\" foobar \"foo"
var result = Regex.Split(test, " (?=(?:[^"]*"[^"]*")*[^"]*$)");

这将使:

foo bar "foo
bar" foobar "foo

因为它从最后开始并向后运行过滤器。我需要结果:

foo
bar
"foo bar"
foobar
"foo

我知道$负责最后的事情,但我不能为我的生活弄清楚如何扭转它。想法?

4 个答案:

答案 0 :(得分:1)

分割时可以使用此正则表达式。

("[^"]+"|\s+)

如果将模式括在括号内,则大多数拆分函数将返回使用的分隔符。在这种情况下,您首先尝试在当前位置匹配带引号的单词,如果您无法匹配,则选择匹配空格。

获得所有值后,只需删除那些仅包含要丢弃的分隔符的值(在这种情况下为空格)。

以下是使用Perl的示例。

use warnings;
use strict;

my $string = "foo bar \"foo bar\" foobar \"foo";

my @array =  grep { ! /^\s*$/ } # Discard matches containing only spaces.
                 split /("[^"]+"|\s+)/, $string; # Split on whitespace or character withing quotes
                                         # Return delimiters as part of the match.    

print "$_\n" foreach @array;

<强>输出

foo
bar
"foo bar"
foobar
"foo

答案 1 :(得分:1)

它实际上并不向后运行,只是前瞻必须在每次应用时都一直匹配到最后。这是唯一可以确定在当前位置之后有偶数引号的方式。

但这无论如何都是一个黑客的解决方案;只有当你被迫使用Split()时才应该做的事情。匹配令牌本身通常要容易得多。例如:

string s = @"foo bar ""foo bar"" foobar ""foo";
Regex r = new Regex(@"[^""\s]+|""[^""]+(?:""|$)");

foreach (Match m in r.Matches(s))
{
  Console.WriteLine(m.Value);
}

输出:

foo
bar
"foo bar"
foobar
"foo

编辑:此版本允许不带引号的令牌包含引号:

@"[^""\s]\S+|""[^""]+(?:""|$)"

我仍然假设不带引号的令牌不能包含任何空格。


编辑:似乎引号一直是特殊的,而不仅仅是它们是令牌中的第一个非空白字符。在此版本中,令牌可能以非引号开头或结尾,而可能包含一个或多个带引号的序列。因为所有内容都是可选的,所以它以前瞻开头,以防止它匹配空字符串。

@"(?=\S)[^\s""]*(?:""[^""]+(?:$|""[^\s""]*))*"

和以前一样,最终的收盘价是可选的。

答案 2 :(得分:0)

如果您尝试使用此方法

,该怎么办?
string test = "foo bar \"foo bar\" foobar \"foo";
if (test.Count(q => q == '"')%2 == 1)
    test += "\"";

test = Regex.Replace(test, "\"[^\"]+\"", "");

测试它是否有奇数引号,如果有,则加一。然后使用"\"[^\"]+\""删除引号内的任何内容。然后你可以使用String.Split()

自由地拆分它

答案 3 :(得分:0)

我认为Regex 1或Regex 2应该可以解决问题。

 # =====================================
 # Regex 1
 # =====================================
 #    ("[^"]")|[\s=]+             // raw
 #    "(\"[^\"]\")|[\\s=]+"       // escped
 #    @"                          // verbatim
 #     (""[^""]"")|[\s=]+
 #    "
 # -------------------------------------
 #    
 #         ( " [^"] " )      # expanded Regex 1
 #      |  
 #         [\s=]+ 

 # =====================================
 # Regex 2
 # =====================================
 #    ("(?:[^"]*"[^"]*")*[^"]*")|[\s=]+             // raw
 #    "(\"(?:[^\"]*\"[^\"]*\")*[^\"]*\")|[\\s=]+"   // escaped
 #    @"                                            // verbatim
 #     (""(?:[^""]*""[^""]*"")*[^""]*"")|[\s=]+
 #    "
 # -------------------------------------
 #        
 #        (                  # expanded Regex 2
 #             " 
 #             (?: [^"]* " [^"]* " )*
 #             [^"]* 
 #             "     
 #        )
 #     |  
 #        [\s=]+