正则表达式匹配空格,但不在“字符串”中

我正在寻找一个常规的exression匹配空格,只有当thos空格没有用双引号(“)括起来时。例如,在

Mary had "a little lamb" 

它应该匹配第一个和第二个空间,而不是其他空间。

我想将字符串拆分在不在双引号中的空格处,而不是在引号处。

我正在使用C ++与Qt工具包,并希望使用QString :: split(QRegExp)。 QString与std :: string非常相似,而QRegExp基本上是封装在类中的POSIX正则表达式。 如果存在这样的正则表达式,那么拆分将是微不足道的。

例子:

 Mary had "a little lamb" => Mary,had,"a little lamb" 1" 2 "3 => 1" 2 "3 (no splitting at ") abc def="ghi" "jk" = 12 => abc,def="ghi","jk",=,12 

对于编辑很抱歉,当我首先提出问题时,我非常不精确。 希望现在更加清晰。

(我知道你自己刚刚发布了几乎完全相同的答案,但是我不忍心把这一切都丢掉。: – /)

如果可以通过正则表达式拆分操作解决您的问题,正则表达式将必须匹配偶数个引号,正如MSalters所说。 但是,拆分正则表达式应仅匹配您正在拆分的空间,因此其余工作必须在前瞻中完成。 这是我会用的:

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

如果文本格式正确,则偶数引号的前瞻足以确定刚刚匹配的空间不在引用序列中。 也就是说,不需要lookbehinds,这很好,因为QRegExp似乎不支持它们。 转义报价也可以适应,但正则表达式变得更大,更丑陋。 但是如果你不能确定文本是否格式正确,那么你就不太可能用split()来解决你的问题。

顺便说一句,QRegExp 没有实现POSIX正则表达式 -如果它这样做,它将不支持前瞻或后观。 相反,它属于松散定义的Perl兼容正则表达式类别。

"a" b "c"会发生什么?

请注意,在子字符串" b " ,空格在引号之间。

– 编辑 –

我假设一个空格是“引号之间”,如果它前面跟着奇数个标准引号(即U + 0022,我将忽略那些有趣的Unicode“引号”)。

这意味着你需要以下正则表达式: ^[^"]*("[^"]*"[^"]*)*"[^"]* [^"]*"[^"]*("[^"]*"[^"]*)*$

("[^"]*"[^"]*)表示一对引号。 ("[^"]*"[^"]*)*是偶数引号, ("[^"]"[^"]*)*"奇数。然后是实际引用的字符串部分,其次是通过另一个奇数引号。 ^$锚是必需的,因为你需要从字符串的开头计算每个引用。这通过从不查看子串回答上面的" b "子串问题。价格是输入中的每个字符必须与整个字符串匹配,从而将其转换为O(N * N)分割操作。

您可以在正则表达式中执行此操作的原因是因为需要有限量的内存。 实际上只有一点; “到目前为止,我看到过奇数或偶数的报价吗?” 你实际上不必匹配单个""对。

不过,这不是唯一可能的解释。 如果你确实包括应该配对的“funny Unicode quotes” ,你还需要处理““double quoted””字符串。 这反过来意味着你需要一个开放计数 ,这意味着你需要无限存储,这反过来意味着它不再是常规语言,这意味着你不能使用正则表达式。 QED。

无论如何,即使有可能,你仍然需要一个合适的解析器。 用于计算每个字符前面的引号数的O(N * N)行为并不好笑。 如果你已经知道在Str [N]之前有X引号,那么它应该是一个O(1)操作来确定在Str [N + 1]之前有多少引号,而不是O(N)。 可能的答案毕竟只是X或X + 1!

MSalters推动我走上正轨。 他回答的问题是他给出的正则表达式总是匹配整个字符串,因此不适合split(),但这可以部分地通过先行匹配来兑换。 假设引号总是配对(它们确实是),我可以在每个空格分开, 后面跟着偶数引号。

没有C转义的正则表达式和单引号看起来像

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

在源代码中它最终看起来像(使用Qt和C ++)

 QString buf("Mary had \"a little lamb\""); // string we want to split QStringList splitted = buf.split( QRegExp(" (?=[^\"]*(\"[^\"]*\"[^\"]*)*$)") ); 

简单,嗯?

对于性能,字符串在程序开始时被解析一次,它们是几十个并且它们不到100个字符。 我会用长字符串测试它的运行时,只是为了确保没有发生任何不好的事情;-)

如果字符串中的引用很简单(如示例所示),则可以使用交替。 这个正则表达式首先捕获一个简单的引用字符串; 没有找到空格。

 /(\"[^\"]*\"| +)/ 

在Perl中,如果在调用split()时在正则表达式中使用分组,则该函数不仅返回元素,还返回捕获的组(在本例中为我们的分隔符)。 如果您然后过滤掉空白和仅空格分隔符,您将获得所需的元素列表。 我不知道类似的策略是否适用于C ++,但以下Perl代码确实有效:

 use strict; use warnings; while (){ chomp; my @elements = split /(\"[^\"]*\"| +)/, $_; @elements = grep {length and /[^ ]/} @elements; # Do stuff with @elements } __DATA__ Mary had "a little lamb" 1" 2 "3 abc def="ghi" "jk" = 12 

最简单的正则表达式解决方案:匹配整个空格和引号。 稍后过滤报价

 "[^"]*"|\s