我正在寻找一个常规的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="g h i" "j k" = 12 => abc,def="g h i","j k",=,12
对于编辑很抱歉,当我首先提出问题时,我非常不精确。希望现在更清楚一点。
答案 0 :(得分:7)
(我知道你刚刚发布了几乎完全相同的答案,但我不忍心把这一切都丢掉。: - /)
如果可以通过正则表达式拆分操作解决您的问题,正则表达式将必须匹配偶数个引号,正如MSalters所说。但是,拆分正则表达式应仅匹配您正在拆分的空间,因此其余工作必须在前瞻中完成。这是我要用的:
" +(?=(?:[^\"]*\"[^\"]*\")*[^\"]*$)"
如果文本格式正确,则偶数引号的前瞻足以确定刚刚匹配的空间不在引用序列中。也就是说,lookbehinds不是必需的,这很好,因为QRegExp似乎不支持它们。转义报价也可以适应,但正则表达式变得更大,更丑陋。但是,如果您无法确定文本是否格式正确,那么您很可能无法使用split()
来解决问题。
顺便说一句,QRegExp 不实现POSIX regular expressions - 如果确实如此,它将不支持前瞻或后观。相反,它属于松散定义的Perl兼容正则表达式类别。
答案 1 :(得分:4)
"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!
答案 2 :(得分:4)
MSalters推动我走上正轨。他回答的问题是他给出的正则表达式总是匹配整个字符串,因此不适合split(),但这可以部分地通过先行匹配来兑换。假设引号总是配对(确实是这样),我可以在每个空格上拆分,然后是偶数个引号。
没有C转义且单引号的正则表达式看起来像
' (?=[^"]*("[^"]*"[^"]*)*$)'
在源代码中它最终看起来像(使用Qt和C ++)
QString buf("Mary had \"a little lamb\""); // string we want to split
QStringList splitted = buf.split( QRegExp(" (?=[^\"]*(\"[^\"]*\"[^\"]*)*$)") );
简单,嗯?
对于性能,字符串在程序开始时被解析一次,它们是几十个并且它们不到100个字符。我将用长字符串测试它的运行时间,以确保没有任何不好的事情发生; - )
答案 3 :(得分:1)
如果字符串中的引用很简单(如示例所示),则可以使用交替。这个正则表达式首先寻找一个简单的引用字符串;没有找到空格。
/(\"[^\"]*\"| +)/
在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
答案 4 :(得分:-2)
最简单的正则表达式解决方案:匹配整个空格和引号。稍后过滤报价
"[^"]*"|\s