这是一个有趣的场景。通常,您最好从主源中提取字符串 start(.*)end,然后在子字符串上运行 RegEx。
但这并不意味着不可能使用一个 RegEx!
我确定您已经为 positive|negative lookahead|lookbehind 苦苦挣扎,并发现您无法进行动态长度后视,这真的很麻烦,例如(?<=start.*) 和 lookahead 一样。
对于此示例,您必须了解的关键是 RegEx 在匹配时将 cursor 位置移动到字符串中...这是我们将用来完成这项工作的警告。
正则表达式
(?:.*start|^.*|end.*)|\b(\w{3,})(?=.*end)
(?: : Start of non-capture group
.*start : [Match pattern 1a] matches anything upto and including the {start} anchor
| : OR operator
^.* : [Match pattern 1b] matches from the {^} start of the string to the end
| : OR operator
end.* : [Match pattern 1c] matches from the {end} anchor to the end of the string
) : End of non-capture group
| : OR operator
\b(\w{3,})(?=.*end) : Captures a boundary [\b] followed by word characters [a-zA-Z0-9_] 3 or more times whilst using a positive lookahead to check that the {end} anchor hasn't been passed
冗长的解释
上面的RegEx可以写成,简单来说:
NON-CAPTURING_GROUP OR CAPTURING_GROUP
OR, more verbose
(MATCH_PATTERN_1a OR MATCH_PATTERN_1b OR MATCH_PATTERN_1c) OR MATCH_PATTERN_2
-
NON-CAPTURING_GROUP 总是首先被评估,所以我们在这里检查我们实际上想要得到匹配
-
MATCH_PATTERN_1a 检查 start 锚点是否存在,并将 cursor 移动到字符串中的那个点
-
MATCH_PATTERN_1b 仅在 1a 失败且字符串中存在 start 锚点时匹配。如果是这样,它匹配所有内容并且表达式停止。
-
MATCH_PATTERN_1c 检查未到达 end 锚点。如果匹配,则匹配到字符串的末尾并且表达式停止。
-
CAPTURING_GROUP 总是排在第二位;所以只匹配如果它应该
-
MATCH_PATTERN_2 匹配任何单词边界,后跟单词字符 [a-zA-Z0-9_] 在指定长度之间
- 它还会检查
positive lookahead 以确保 end 锚未通过
警告
请注意,第一个和最后一个捕获将始终来自 NON-CAPTURE 组,应该被忽略。根据 regex 的实现方式,它可能是空的、完整的匹配字符串或两者(多维数组)。
示例 [Python]
注意:Python 以$result = $full_matches[] 格式输出
注意:flag = re.I 已设置为使 RegEx 不区分大小写,即它匹配 START 和 start
import re
test_str1 = """one two three four START four five two five six END seven"""
test_str2 = """this is the start some words are to be selected end no more select"""
test_str3 = """these are some words that shouldn't be selected end also not selected"""
test_str4 = """end two four five two five six END seven"""
test_str5 = """one start two three end four five six end seven one"""
test_str6 = """END START two four five two five six seven"""
regex1 = r"(?:.*start|^.*|end.*)|\b(\w{3,})(?=.*end)"
regex2 = r"(?:.*start|^.*|end.*)|\b(\w{4,})(?=.*end)"
print(re.findall(regex1, test_str1, re.I))
print(re.findall(regex1, test_str2, re.I))
print(re.findall(regex1, test_str3, re.I))
print(re.findall(regex1, test_str4, re.I))
print(re.findall(regex1, test_str5, re.I))
print(re.findall(regex1, test_str6, re.I))
print(re.findall(regex2, test_str1, re.I))
print(re.findall(regex2, test_str2, re.I))
print(re.findall(regex2, test_str3, re.I))
print(re.findall(regex2, test_str4, re.I))
print(re.findall(regex2, test_str5, re.I))
print(re.findall(regex2, test_str6, re.I))
'''
Output:
['', 'four', 'five', 'two', 'five', 'six', '']
['', 'some', 'words', 'are', 'selected', '']
['']
['']
['', 'two', 'three', '']
['']
['', 'four', 'five', 'five', '']
['', 'some', 'words', 'selected', '']
['']
['']
['', 'three', '']
['']
'''
示例 [PHP]
注意:PHP 以$result = [$full_matches[], $capture_group[]] 格式输出
注意:flag = i 已设置为使 RegEx 不区分大小写,即它匹配 START 和 start
$test_str1 = "one two three four START four five two five six END seven";
$test_str2 = "this is the start some words are to be selected end no more select";
$test_str3 = "these are some words that shouldn't be selected end also not selected";
$test_str4 = "end two four five two five six END seven";
$test_str5 = "one start two three end four five six end seven one";
$test_str6 = "END START two four five two five six seven";
$regex1 = "/(?:.*start|^.*|end.*)|\b(\w{3,})(?=.*end)/i";
$regex2 = "/(?:.*start|^.*|end.*)|\b(\w{4,})(?=.*end)/i";
preg_match_all($regex1, $test_str1, $matches1);
preg_match_all($regex1, $test_str2, $matches2);
preg_match_all($regex1, $test_str3, $matches3);
preg_match_all($regex1, $test_str4, $matches4);
preg_match_all($regex1, $test_str5, $matches5);
preg_match_all($regex1, $test_str6, $matches6);
preg_match_all($regex2, $test_str1, $matches7);
preg_match_all($regex2, $test_str2, $matches8);
preg_match_all($regex2, $test_str3, $matches9);
preg_match_all($regex2, $test_str4, $matches10);
preg_match_all($regex2, $test_str5, $matches11);
preg_match_all($regex2, $test_str6, $matches12);
echo json_encode($matches1);
echo "\n";
echo json_encode($matches2);
echo "\n";
echo json_encode($matches3);
echo "\n";
echo json_encode($matches4);
echo "\n";
echo json_encode($matches5);
echo "\n";
echo json_encode($matches6);
echo "\n";
echo json_encode($matches7);
echo "\n";
echo json_encode($matches8);
echo "\n";
echo json_encode($matches9);
echo "\n";
echo json_encode($matches10);
echo "\n";
echo json_encode($matches11);
echo "\n";
echo json_encode($matches12);
/*
Output:
[["one two three four START","four","five","two","five","six","END seven"],["","four","five","two","five","six",""]]
[["this is the start","some","words","are","selected","end no more select"],["","some","words","are","selected",""]]
[["these are some words that shouldn't be selected end also not selected"],[""]]
[["end two four five two five six END seven"],[""]]
[["one start","two","three","end four five six end seven one"],["","two","three",""]]
[["END START"],[""]]
[["one two three four START","four","five","five","END seven"],["","four","five","five",""]]
[["this is the start","some","words","selected","end no more select"],["","some","words","selected",""]]
[["these are some words that shouldn't be selected end also not selected"],[""]]
[["end two four five two five six END seven"],[""]]
[["one start","three","end four five six end seven one"],["","three",""]]
[["END START"],[""]]
*/
.NET
如果您使用的是.NET,那么 RegEx 会变得简单得多:
start(\s*(?!end)\w+\s*)*end
这是因为.NET 允许您捕获所有出现的回避字符串。
其他方法
实际上,您最好将字符串拆分为子字符串并从那里进行评估...
输入
start one two three end start one two three end one two end
拆分字符串
start(.*?)end
[0] => start one two three end
[1] => start one two three end one two end
匹配单词
\b\w{3,}
示例
$string = "start one two three end start four five six end one two end";
preg_match_all('/start(.*?)end/i', $string, $matches);
foreach($matches[1] as $match){
preg_match_all('/\b\w{3,}/', $match, $out);
var_dump($out);
}
/*
Output:
array(1) {
[0]=>
array(3) {
[0]=>
string(3) "one"
[1]=>
string(3) "two"
[2]=>
string(5) "three"
}
}
array(1) {
[0]=>
array(3) {
[0]=>
string(4) "four"
[1]=>
string(4) "five"
[2]=>
string(3) "six"
}
}
*/