如何在正则表达式中捕获可选组?
How can I capture an optional group in regex?
我有一个正则表达式如下:
const verseRegex = /(?<chapterBegin>[^\d+$]*):(?<verseBegin>[^\d+$]*)-((?<chapterEnd>[^\d+$]*):)?(?<verseEnd>[^\d+$]*)/g;
我希望正则表达式能够匹配以下两个字符串:
4:1-13
4:1-5:20
然而,正则表达式只能匹配第一个字符串并将其正确分组:
console.log(verseRegex.exec('4:1-13');
[
'4:1-13',
'4',
'1',
undefined,
undefined,
'13',
index: 0,
input: '4:1-13',
groups: [Object: null prototype] {
chapterBegin: '4',
verseBegin: '1',
chapterEnd: undefined,
verseEnd: '13'
}
]
对于第二个字符串 null
返回。
我对上述行为没有任何解释。当我删除可选组并将我的正则表达式重写为:
const verseRegex = /(?<chapterBegin>[^\d+$]*):(?<verseBegin>[^\d+$]*)-(?<chapterEnd>[^\d+$]*):(?<verseEnd>[^\d+$]*)/g;
现在第二个字符串按预期匹配和分组,第一个字符串失败,因为 chapterEnd
组不再是可选的。
我如何重写我的正则表达式以便它匹配和分组两个字符串?
注意 [^\d+$]*
模式匹配除 \
、d
、+
和 $
字符之外的任何字符。你一定是想匹配一个或多个数字块,所以你需要 \d+
.
您可以使用
/^(?<chapterBegin>\d+):(?<verseBegin>\d+)-(?:(?<chapterEnd>\d+):)?(?<verseEnd>\d+)$/
或者,没有命名的捕获组(例如,对于 IE):
/^(\d+):(\d+)-(?:(\d+):)?(\d+)$/
查看 JavaScript 演示:
const strs = ['4:1-13','4:1-5:20'];
const rx = /^(?<chapterBegin>\d+):(?<verseBegin>\d+)-(?:(?<chapterEnd>\d+):)?(?<verseEnd>\d+)$/;
for (let s of strs) {
const results = rx.exec(s);
console.log(s, results.groups);
}
输出:
4:1-13 {
"chapterBegin": "4",
"verseBegin": "1",
"chapterEnd": undefined,
"verseEnd": "13"
}
4:1-5:20 {
"chapterBegin": "4",
"verseBegin": "1",
"chapterEnd": "5",
"verseEnd": "20"
}
旧浏览器演示:
var strs = ['4:1-13','4:1-5:20'];
var rx = /^(\d+):(\d+)-(?:(\d+):)?(\d+)$/;
for (var i=0; i<strs.length; i++) {
var results = rx.exec(strs[i]);
console.log(strs[i], results);
}
我有一个正则表达式如下:
const verseRegex = /(?<chapterBegin>[^\d+$]*):(?<verseBegin>[^\d+$]*)-((?<chapterEnd>[^\d+$]*):)?(?<verseEnd>[^\d+$]*)/g;
我希望正则表达式能够匹配以下两个字符串:
4:1-13
4:1-5:20
然而,正则表达式只能匹配第一个字符串并将其正确分组:
console.log(verseRegex.exec('4:1-13');
[
'4:1-13',
'4',
'1',
undefined,
undefined,
'13',
index: 0,
input: '4:1-13',
groups: [Object: null prototype] {
chapterBegin: '4',
verseBegin: '1',
chapterEnd: undefined,
verseEnd: '13'
}
]
对于第二个字符串 null
返回。
我对上述行为没有任何解释。当我删除可选组并将我的正则表达式重写为:
const verseRegex = /(?<chapterBegin>[^\d+$]*):(?<verseBegin>[^\d+$]*)-(?<chapterEnd>[^\d+$]*):(?<verseEnd>[^\d+$]*)/g;
现在第二个字符串按预期匹配和分组,第一个字符串失败,因为 chapterEnd
组不再是可选的。
我如何重写我的正则表达式以便它匹配和分组两个字符串?
注意 [^\d+$]*
模式匹配除 \
、d
、+
和 $
字符之外的任何字符。你一定是想匹配一个或多个数字块,所以你需要 \d+
.
您可以使用
/^(?<chapterBegin>\d+):(?<verseBegin>\d+)-(?:(?<chapterEnd>\d+):)?(?<verseEnd>\d+)$/
或者,没有命名的捕获组(例如,对于 IE):
/^(\d+):(\d+)-(?:(\d+):)?(\d+)$/
查看 JavaScript 演示:
const strs = ['4:1-13','4:1-5:20'];
const rx = /^(?<chapterBegin>\d+):(?<verseBegin>\d+)-(?:(?<chapterEnd>\d+):)?(?<verseEnd>\d+)$/;
for (let s of strs) {
const results = rx.exec(s);
console.log(s, results.groups);
}
输出:
4:1-13 {
"chapterBegin": "4",
"verseBegin": "1",
"chapterEnd": undefined,
"verseEnd": "13"
}
4:1-5:20 {
"chapterBegin": "4",
"verseBegin": "1",
"chapterEnd": "5",
"verseEnd": "20"
}
旧浏览器演示:
var strs = ['4:1-13','4:1-5:20'];
var rx = /^(\d+):(\d+)-(?:(\d+):)?(\d+)$/;
for (var i=0; i<strs.length; i++) {
var results = rx.exec(strs[i]);
console.log(strs[i], results);
}