正如标题中所述,是否有一种方法,使用正则表达式来匹配出现在引号之外的文本的文本模式。理想情况下,给出以下示例,我希望能够匹配引号之外的逗号,但不能匹配引号中的逗号。
这是一些文字,后跟“文字,引号!”
或
这是一些文字,后跟“带引号的文字”,带有更多“文字,引号!”
此外,如果表达式遵循嵌套引号会很好,如下例所示。但是,如果这在技术上不适用于正则表达式,那么很容易知道是否是这种情况。
程序员从他的办公桌上抬起头,“这不可能很好,”他大声说道,“系统正在说'找不到文件!'”
我找到了一些用于匹配引号中某些内容的表达式,但对引号之外的内容没什么用。
答案 0 :(得分:4)
最简单的是匹配逗号和引用的字符串,然后过滤掉引用的字符串。
/"[^"]*"|,/g
如果你真的不能匹配引号,你可以这样做:
/,(?=[^"]*(?:"[^"]*"[^"]*)*\Z)/g
这可能会变慢,因为对于每个逗号,它必须查看剩余的字符并计算引号的数量。 \Z
匹配字符串的结尾。与$
类似,但永远不会匹配行结束。
如果您不介意额外的捕获组,可以这样做:
/\G((?:[^"]*"[^"]*")*?[^"]*?)(,)/g
这只会扫描一次字符串。它从字符串的开头开始计算引号。 \G
将匹配上次匹配结束的位置。
最后一个模式可能需要一个例子。
Input String: 'This is, some text, followed by "text, in quotes!" and more ,-as'
Matches:
1. ['This is', ',']
2. [' some text', ',']
3. [' and followed by "text, in quotes!" and more ', ',']
它匹配前导到逗号的字符串以及逗号。
答案 1 :(得分:2)
这可以通过现代正则表达式完成,因为存在大量的正则表达式引擎,但让我成为发布“不要使用正则表达式”答案的人。
这是不正则表达式的作业。这是一个完整的解析器的工作。作为一些你不能用(经典)正则表达式做的事情的例子,请考虑这个:
()(())(()())
没有(经典)正则表达式可以确定这些括号是否匹配正确,但没有正则表达式这样做是微不足道的:
/* C code */
char string[] = "()(())(()())";
int parens = 0;
for(char *tmp = string; tmp; tmp++)
{
if(*tmp == '(') parens++;
if(*tmp == ')') parens--;
}
if(parens > 0)
{
printf("%s too many open parenthesis.\n", parens);
}
else if(parens < 0)
{
printf("%s too many closing parenthesis.\n", -parens);
}
else
{
printf("Parenthesis match!\n");
}
# Perl code
my $string = "()(())(()())";
my $parens = 0;
for(split(//, $string)) {
$parens++ if $_ eq "(";
$parens-- if $_ eq ")";
}
die "Too many open parenthesis.\n" if $parens > 0;
die "Too many closing parenthesis.\n" if $parens < 0;
print "Parenthesis match!";
看一下编写一些非正则代码来为你完成这项工作有多简单?
编辑:好的,从看到探险世界回来了。 :)尝试这个(用Perl编写,评论是为了帮助你理解我在做什么,如果你不知道Perl):# split $string into a list, split on the double quote character
my @temp = split(/"/, $string);
# iterate through a list of the number of elements in our list
for(0 .. $#temp) {
# skip odd-numbered elements - only process $list[0], $list[2], etc.
# the reason is that, if we split on "s, every other element is a string
next if $_ & 1;
if($temp[$_] =~ /regex/) {
# do stuff
}
}
另一种方法:
my $bool = 0;
my $str;
my $match;
# loop through the characters of a string
for(split(//, $string)) {
if($_ eq '"') {
$bool = !$bool;
if($bool) {
# regex time!
$match += $str =~ /regex/;
$str = "";
}
}
if(!$bool) {
# add the current character to our test string
$str .= $_;
}
}
# get trailing string match
$match += $str =~ /regex/;
(我给出了两个,因为在另一种语言中,一种解决方案可能比另一种解决方案更容易实现,而不仅仅是因为有多种方法可以做到这一点。)
当然,随着你的问题越来越复杂,构建一个完整的解析器会产生某些好处,但这是一个不同的马。现在,这就足够了。
答案 2 :(得分:1)
如前所述regexp cannot match any nested pattern,因为它不是Context-free language。
因此,如果你有任何嵌套引号,你就不会用正则表达式解决这个问题 (除了。{regex引擎的“balancing group”功能之外 - 正如Daniel L在评论中所提到的那样 - 但我在这里没有假设正则表达式的风格)
除非您添加进一步的规范,否则必须转义报价中的报价。
在这种情况下,以下内容:
text before string "string with \escape quote \" still
within quote" text outside quote "within quote \" still inside" outside "
inside" final outside text
将成功匹配:
(?ms)((?:\\(?=")|[^"])+)(?:"((?:[^"]|(?<=\\)")+)(?<!\\)")?
\"
。答案 3 :(得分:0)
这是一个获得匹配的表达式,但它并不完美,因为它获得的第一个匹配是整个字符串,删除最后的“。
[^"].*(,).*[^"]
我一直在使用我的Free RegEx tester来查看哪些有用。
测试结果
Group Match Collection # 1
Match # 1
Value: This is some text, followed by "text, in quotes!
Captures: 1
Match # 2
Value: ,
Captures: 1
答案 4 :(得分:0)
你最好自己构建一个简单的解析器(伪代码):
quoted := False
FOR char IN string DO
IF char = '"'
quoted := !quoted
ELSE
IF char = "," AND !quoted
// not quoted comma found
ENDIF
ENDIF
ENDFOR
答案 5 :(得分:0)
这实际上取决于您是否允许嵌套引号。
理论上,使用嵌套引号你不能这样做(常规语言不能计算)
在实践中,您可以管理是否可以约束深度。随着您增加复杂性,它将变得越来越难看。这通常是人们如何通过正则表达式(试图匹配一般不常规的东西)来解决悲伤的方式。
请注意,某些“正则表达式”库/语言添加了非常规功能。
如果这种事情变得足够复杂,你真的必须为它编写/生成一个解析器。
答案 6 :(得分:0)
您的描述中需要更多内容。你想要任何可能的引用字符串和非引用的字符串吗...
Lorem ipsum“dolor sit”amet,“consectetur adipiscing”elit。
......或者只是你要求的模式?我认为这非常接近......
(?<outside>.*?)(?<inside>(?=\"))
然而它确实抓住了“。”
答案 7 :(得分:0)
也许你可以分两步完成? 首先,您替换引用的文本:
("[^"]*")
然后从剩余的字符串
中提取您想要的内容答案 8 :(得分:0)
,(?=(?:[^"]*"[^"]*")*[^"]*\z)
正则表达式可能无法计算,但它们可以确定是否存在奇数或偶数。在找到一个逗号之后,前瞻断言,如果前面有任何引号,则会有偶数个引号,这意味着逗号在一组引号中不。
如果需要,可以调整这个来处理转义引号,尽管最初的问题没有提到。此外,如果你的正则表达式支持它们,我会添加原子组或占有量词来控制回溯。