我正在尝试在 JavaScript 中评论正则表达式。
似乎有很多关于如何使用正则表达式从代码中删除注释的资源,但实际上并没有如何在 JavaScript 中注释正则表达式,因此它们更容易理解。
我正在尝试在 JavaScript 中评论正则表达式。
似乎有很多关于如何使用正则表达式从代码中删除注释的资源,但实际上并没有如何在 JavaScript 中注释正则表达式,因此它们更容易理解。
不幸的是,JavaScript 没有像其他语言那样的正则表达式文字的详细模式。不过,您可能会觉得这很有趣。
代替任何外部库,最好的办法是使用普通字符串并注释:
var r = new RegExp(
'(' + //start capture
'[0-9]+' + // match digit
')' //end capture
);
r.test('9'); //true
虽然 Javascript 本身不支持多行和带注释的正则表达式,但构造完成相同事情的东西很容易 - 使用一个函数接收(多行,带注释的)字符串并从该字符串返回正则表达式, 没有注释和换行符。
以下代码段模仿其他风格x
(“扩展”)标志的行为,它忽略模式中的所有空白字符以及注释,用 表示#
:
function makeExtendedRegExp(inputPatternStr, flags) {
// Remove everything between the first unescaped `#` and the end of a line
// and then remove all unescaped whitespace
const cleanedPatternStr = inputPatternStr
.replace(/(^|[^\\])#.*/g, '$1')
.replace(/(^|[^\\])\s+/g, '$1');
return new RegExp(cleanedPatternStr, flags);
}
// The following switches the first word with the second word:
const input = 'foo bar baz';
const pattern = makeExtendedRegExp(String.raw`
^ # match the beginning of the line
(\w+) # 1st capture group: match one or more word characters
\s # match a whitespace character
(\w+) # 2nd capture group: match one or more word characters
`);
console.log(input.replace(pattern, '$2 $1'));
通常,要在 Javascript 字符串中表示反斜杠,必须对每个文字反斜杠进行双重转义,例如str = 'abc\\def'
. 但是正则表达式经常使用很多反斜杠,而双重转义会使模式的可读性大大降低,所以在编写带有很多反斜杠的 Javascript 字符串时,最好使用String.raw
模板字面量,它允许单个类型的反斜杠实际表示一个字面反斜杠,无需额外转义。
就像使用标准x
修饰符一样,要匹配#
字符串中的实际值,只需先将其转义即可,例如
foo\#bar # comments go here
请注意,要匹配文字空格字符(而不仅仅是任何空白字符),x
在任何环境(包括上述环境)中使用标志时,您必须使用\
第一个对空格进行转义,例如:
^(\S+)\ (\S+) # capture the first two words
如果您想频繁匹配空格字符,这可能会变得有点乏味并使模式更难阅读,类似于双重转义反斜杠不是很可取。允许未转义空格字符的一种可能(非标准)修改是仅去除行首和行尾的空格以及#
注释前的空格:
function makeExtendedRegExp(inputPatternStr, flags) {
// Remove the first unescaped `#`, any preceeding unescaped spaces, and everything that follows
// and then remove leading and trailing whitespace on each line, including linebreaks
const cleanedPatternStr = inputPatternStr
.replace(/(^|[^\\]) *#.*/g, '$1')
.replace(/^\s+|\s+$|\n/gm, '');
console.log(cleanedPatternStr);
return new RegExp(cleanedPatternStr, flags);
}
// The following switches the first word with the second word:
const input = 'foo bar baz';
const pattern = makeExtendedRegExp(String.raw`
^ # match the beginning of the line
(\w+) (\w+) # capture the first two words
`);
console.log(input.replace(pattern, '$2 $1'));
在其他几种语言(特别是 Perl)中,有一个特殊的x
标志。设置后,正则表达式会忽略其中的任何空格和注释。遗憾的是,javascript regexp 不支持该x
标志。
缺乏语法,利用可读性的唯一方法是约定。我的方法是在棘手的正则表达式之前添加一条注释,将其包含在内,就好像您拥有 x 标志一样。例子:
/*
\+? #optional + sign
(\d*) #the integeric part
( #begin decimal portion
\.
\d+ #decimal part
)
*/
var re = /\+?(\d*)(\.\d+)/;
在2021年,我们可以利用这样做模板文字具有String.raw()适用于它。
VerboseRegExp `
(
foo* // zero or more foos
(?: bar | baz ) // bar or baz
quux? // maybe a quux
)
\s \t \r \n \[ \] \/ \` // invisible whitespace is ignored ...
[ ] // ... unless you put it in a character class
`
`gimy` // flags go here
// returns the RegExp /(foo*(?:bar|baz)quux?)\s\t\r\n\[\]\/\`[ ]/gimy
的实施VerboseRegExp
:
const VerboseRegExp = (function init_once () {
const cleanupregexp = /(?<!\\)[\[\]]|\s+|\/\/[^\r\n]*(?:\r?\n|$)/g
return function first_parameter (pattern) {
return function second_parameter (flags) {
flags = flags.raw[0].trim()
let in_characterclass = false
const compressed = pattern.raw[0].replace(
cleanupregexp,
function on_each_match (match) {
switch (match) {
case '[': in_characterclass = true; return match
case ']': in_characterclass = false; return match
default: return in_characterclass ? match : ''
}
}
)
return flags ? new RegExp(compressed, flags) : new RegExp(compressed)
}
}
})()
请参阅JavaScript 中的详细正则表达式了解其.raw[0]
作用。
我建议您在带有正则表达式的行上方放置一个正则注释,以便对其进行解释。
你将拥有更多的自由。