在我开始之前,我知道已经有很多关于这个主题的线程创建了,但我找不到任何特定于我的用例的东西,因此我想根据我的发现用一个实际的例子来问这个问题。
我有一个多行字符串,其中包含我感兴趣的内容:
hello: "
-foo=value1
-bar=value2
-baz="value3"
"
我想在多行字符串中的特定内容上匹配group,这样它就可以在这个字符串中以-
开头的任何内容上匹配。条件是:
- 必须以单词
hello:
开头 - 对字符串中以
-
开头的每个值进行匹配分组 - 将转义引号视为字符串的一部分:
"
- 字符串也可以作为一个liner,并进行相同的匹配:
hello: "-foo=value1"
我想出了这个模式:
hello:s*"s*-((?:[^"]|n)*)"
不幸的是,它不考虑转义字符串,也不匹配每个结果。我需要匹配的组在该字符串中的每一行上重复。
您可以使用
hello:s*"(?:s*-((?:\.|[^n"\])+))+s*"
请在.NET正则表达式测试仪上查看此正则表达式演示详细信息:
hello:s*"
-hello:
,零个或多个空白,"
(?:s*-((?:\.|[^n"\])+))+
-出现一次或多次:s*-
零次或多次出现空白字符,然后是-
((?:\.|[^n"\])+)
-组1:出现一个或多个转义字符或除、
"
和换行符之外的任何字符
- CCD_ 15-零个或多个空白,然后是CCD_ 16
查看此C#演示:
var s = "hello: "n -foo=value1n -bar=value2n -baz=\"value3\"n"";
var rx = @"hello:s*""(?:s*-((?:\.|[^n""\])+))+s*""";
var result = Regex.Match(s, rx)?.Groups[1].Captures.Cast<Capture>().Select(x => x.Value).ToList();
foreach (var t in result)
Console.WriteLine(t);
请参阅此Python演示:
import regex
s = 'hello: "n -foo=value1n -bar=value2n -baz=\"value3\"n"';
rx = r'hello:s*"(?:s*-((?:\.|[^n"\])+))+s*"';
match = regex.search(rx, s)
if match:
print(match.captures(1))
输出:
foo=value1
bar=value2
baz="value3"
这种方法在围棋中不起作用。您需要使用hello:s*"([^"\]*(?:\[sS][^"\]*)*)"
提取整个匹配,然后使用换行序列拆分Group 1值。
我尝试了一种递归方法来解决这个问题。这是我的解决方案。
我把它作为我的输入文本块,我想它已经捕捉到了所有的可能性:
source_text = """
hello: "
-foo=value1
-bar=value2
-baz="value3"
"
bla: "
-foo=value1
-bar=value2
-baz="value3"
"
hello: "
-foo=value1
-bar=value2
-baz="value3"
"
hello: -baz="value3"
hello: "-foo=value1"
"""
递归匹配正则表达式hello:s("|\")?n?(s*-w+=\?"?w+\?"?n?)+
,该正则表达式捕获match group 2
中所需的文本
import re
all_matches = []
def get_all_matches(text):
for block_match in re.finditer(r'hello:s("|\")?n?(s*-w+=\?"?w+\?"?n?)+', text):
match = block_match.group(2)
if match:
all_matches.append(re.sub("n|\s", '', match))
full_match = block_match.group(0)
get_all_matches(full_match.replace(match, ''))
get_all_matches(source_text)
输出
print(all_matches)
['-baz="value3"', '-bar=value2', '-foo=value1', '-baz="value3"', '-bar=value2', '-foo=value1', '-baz="value3"', '-foo=value1"']