正则表达式拆分空间没有引号向前阅读
本文关键字:拆分 空间 正则表达式 | 更新日期: 2023-09-27 18:37:16
我已经看到很多正则表达式的答案非常接近我的需求,但它并不完全存在。 问题是我有一个字符串,我需要在一个字符上拆分(例如:空格或"="),但我想忽略引号内的任何内容(甚至是引号内的引号)。
我能得到的最接近的是这个:
" (?=(?:[^"]*"[^"]*")*[^"]*$)"
这很好用,但有两个警告:引号中不合时宜的空格会触发错误的拆分,并且它会向后读取。 第一个问题我并不真正关心,我能做的不多,我可以解决它。 但第二个至关重要。
情况是,有时我正在正则表达式的字符串可能会意外地在末尾缺少引号。 这并没有真正打扰我的系统,但是上面的正则表达式倒退了,所以它破坏了一切:
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
我知道 $ 负责结束事情的开始,但我一生都无法弄清楚如何逆转它。 思潮?
它实际上并没有向后运行,只是每次应用时,前瞻都必须一直匹配到最后。 这是确保当前位置后面有偶数报价的唯一方法。
但无论如何,这是一个黑客解决方案; 只有当你被迫使用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""]*))*"
和以前一样,最后的结束报价是可选的。
拆分时使用此正则表达式。
("[^"]+"|'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
如果你尝试这种方法会怎样
string test = "foo bar '"foo bar'" foobar '"foo";
if (test.Count(q => q == '"')%2 == 1)
test += "'"";
test = Regex.Replace(test, "'"[^'"]+'"", "");
测试它是否有奇数个引号,如果有,则添加一个。 然后使用 "'"[^'"]+'""
删除引号内的任何内容。 然后你可以自由地简单地使用String.Split()拆分它
我认为正则表达式 1 或正则表达式 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=]+