C++ 正则表达式匹配空格,但不在“中”;“字符串”;
我正在寻找一个匹配空格的正则表达式,前提是这些空格没有用双引号(“)括起来C++ 正则表达式匹配空格,但不在“中”;“字符串”;,c++,c,regex,qt,C++,C,Regex,Qt,我正在寻找一个匹配空格的正则表达式,前提是这些空格没有用双引号(“)括起来 Mary had "a little lamb" 它应该匹配第一个空格和第二个空格,但不匹配其他空格 我只想在不在双引号中的空格处拆分字符串,而不是在引号中拆分字符串 我使用Qt工具包中的C++,希望使用qString::(QString)与Str::String非常相似:String和QRegExp基本上是封装在一个类中的POSIX正则表达式。如果存在这样的正则表达式,则分裂将是微不足道的。 示例: Mary had
Mary had "a little lamb"
它应该匹配第一个空格和第二个空格,但不匹配其他空格
我只想在不在双引号中的空格处拆分字符串,而不是在引号中拆分字符串
我使用Qt工具包中的C++,希望使用qString::(QString)与Str::String非常相似:String和QRegExp基本上是封装在一个类中的POSIX正则表达式。如果存在这样的正则表达式,则分裂将是微不足道的。 示例:
Mary had "a little lamb" => Mary,had,"a little lamb"
1" 2 "3 => 1" 2 "3 (no splitting at ")
abc def="g h i" "j k" = 12 => abc,def="g h i","j k",=,12
很抱歉编辑,我第一次问这个问题的时候非常不准确。希望现在能更清楚一些。对于
“a”b“c”
该怎么办
请注意,在子字符串“b”
中,空格位于引号之间
--编辑--
我假设一个空格是“引号之间”,如果它前面和后面有奇数个标准引号(即U+0022,我将忽略那些有趣的Unicode“引号”)
这意味着您需要以下正则表达式:^[^”]*(“[^”]*“[^”]*)*“[^”]*[^”]*“[^”]*(“[^”]*“[^”]*)*$
(“[^”]*“[^”]*)
表示一对引号。(“[^”]*“[^”]*)*
是偶数引号,(“[^”]“[^”]*)*”
是奇数引号。然后是实际引用的字符串部分,后面是另一个奇数个引号<代码>^$需要锚定,因为您需要从字符串开始计算每个引号。这通过从不查看子字符串来回答上面的“b”
子字符串问题。代价是输入中的每个字符都必须与整个字符串匹配,这将使其变成一个O(N*N)拆分操作
之所以可以在正则表达式中执行此操作,是因为需要的内存有限。实际上只有一点点;“到目前为止,我看到过奇数或偶数个引号吗?”。实际上,您不必匹配单个“
对
不过,这并不是唯一可能的解释。如果您确实包含了应该配对的“有趣的Unicode引号”
,那么您还需要处理“双引号”
字符串。这反过来意味着您需要一个open“
”计数,这意味着您需要无限的存储空间,这反过来意味着它不再是一种常规语言,这意味着您不能使用regex.QED
无论如何,即使有可能,您仍然需要一个合适的解析器。计算每个字符前面引号数量的O(N*N)行为并不有趣。如果您已经知道Str[N]前面有X个引号,那么确定Str[N+1]前面有多少引号应该是O(1)操作,而不是O(N)。可能的答案毕竟只是X或X+1!最简单的正则表达式解决方案:匹配整个空格和引号。稍后过滤引号
"[^"]*"|\s
如果字符串中的引号很简单(如您的示例),您可以使用alternation。此正则表达式首先查找简单的引号字符串;如果没有,它将查找空格
/(\"[^\"]*\"| +)/
在Perl中,如果在调用split()
时在正则表达式中使用分组,则该函数不仅返回元素,还返回捕获的组(在本例中是分隔符)如果你过滤掉空白和空格只分隔符,你就会得到想要的元素列表。我不知道类似的策略是否在C++中工作,但是下面的Perl代码确实有效:
use strict;
use warnings;
while (<DATA>){
chomp;
my @elements = split /(\"[^\"]*\"| +)/, $_;
@elements = grep {length and /[^ ]/} @elements;
# Do stuff with @elements
}
__DATA__
Mary had "a little lamb"
1" 2 "3
abc def="g h i" "j k" = 12
使用严格;
使用警告;
而(){
咀嚼;
my@elements=split/(\“[^\”]*\“|+)/,$;
@elements=grep{length and/[^]/}@elements;
#使用@elements做一些事情
}
__资料__
玛丽有一只“小羊羔”
1" 2 "3
abc def=“g h i”“j k”=12
MSalters将我推到了正确的轨道上。他的答案中的问题是,他给出的正则表达式总是与整个字符串匹配,因此不适合split(),但这可以通过前瞻匹配部分弥补。假设引号总是成对的(它们确实是),我可以在后面有偶数个引号的每个空格上拆分
不带C转义并使用单引号的正则表达式如下所示
' (?=[^"]*("[^"]*"[^"]*)*$)'
在源代码中,它最终看起来像(使用Qt和C++)
简单,嗯
为了提高性能,字符串在程序开始时会被解析一次,它们只有几十个字符,不到几百个字符。我将用长字符串测试它的运行时间,以确保不会发生什么不好的事情;-)(我知道你自己刚刚发布了几乎完全相同的答案,但我不忍心把这些都扔掉。-/)
如果可以使用正则表达式拆分操作解决您的问题,正则表达式将必须匹配偶数个引号,正如MSalters所说。但是,拆分正则表达式应该只匹配您拆分的空格,因此其余工作必须在前瞻中完成。我将使用以下方法:
" +(?=(?:[^\"]*\"[^\"]*\")*[^\"]*$)"
如果文本格式良好,则对偶数个引号进行先行查找就足以确定刚匹配的空格不在引号序列中。也就是说,没有必要使用lookbehind,这很好,因为QRegExp似乎不支持它们。也可以容纳转义引号,但regex会变得相当大,并且ugl但是如果你不能确定文本的格式是否正确,你就不太可能用split()
解决你的问题
顺便说一句,QRegExp没有实现——如果它实现了,它将不支持lookaheads或lookbehinds。相反,它属于定义松散的Perl兼容正则表达式类。这是一个问题,而不是一个答案。使用注释。这是一个带问号的答案;)问题是他使用了错误的工具(regex而不是基于堆栈的解析器)来解决他的问题。没有“紧密的原因:问题不能用regex解决”我问的原因是因为我想避免使用解析器。我想要“便宜”的解决方案。如果没有使用regex的解决方案,
" +(?=(?:[^\"]*\"[^\"]*\")*[^\"]*$)"