评论正则表达式

问题描述 投票:0回答:7

我正在尝试在 JavaScript 中评论正则表达式。

似乎有很多关于如何使用正则表达式remove代码注释的资源,但实际上没有关于如何在 JavaScript 中comment 正则表达式以便它们更容易理解。

javascript regex comments
7个回答
24
投票

不幸的是,JavaScript 没有像其他一些语言那样的正则表达式文字的冗长模式。不过,您可能会发现这很有趣

代替任何外部库,最好的办法是使用普通字符串并注释:

var r = new RegExp(
    '('      + //start capture
    '[0-9]+' + // match digit
    ')'        //end capture
); 
r.test('9'); //true

10
投票

虽然 Javascript 本身不支持多行和带注释的正则表达式,但构建完成相同功能的东西很容易——使用一个函数,该函数接受一个(多行、带注释的)字符串并从中返回一个正则表达式字符串,没有注释和换行符。

下面的代码片段模仿了其他风格的

x
(“extended”)标志的行为,它忽略了模式中的所有空白字符以及用
#
表示的注释:

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

// this function is exactly the same as the one in the first snippet

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
  \#      # match a hash character
  (\w+)   # 2nd capture group: match one or more word characters
`);
console.log(input.replace(pattern, '$2 $1'));

请注意,要匹配文字空格字符(而不仅仅是 any 空白字符),在任何环境(包括上面)中使用

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'));


5
投票

在其他几种语言(尤其是 Perl)中,有特殊的

x
标志。设置后,正则表达式会忽略其中的任何空格和注释。可悲的是,javascript 正则表达式不支持
x
标志。

缺乏语法,利用可读性的唯一方法是约定。我的方法是在棘手的正则表达式之前添加注释,包含它就像您有 x 标志一样。例子:

/*
  \+?     #optional + sign
  (\d*)   #the integeric part
  (       #begin decimal portion
     \.
     \d+  #decimal part
  )
 */
var re = /\+?(\d*)(\.\d+)/;

对于更复杂的示例,您可以在此处此处看到我使用该技术所做的工作。


4
投票

在 2021 年,我们可以使用 template literals 来做到这一点,它应用了 String.raw()

VerboseRegExp `
    (
        foo*                  // zero or more foos
        (?: bar | baz )       // bar or baz
        quux?                 // maybe a quux
    )
    
    \s \t \r \n \[ \] \\ \/ \`

    H e l l o                 // invisible whitespace is ignored ...
    [ ]                       // ... unless you put it in a character class
    W o r l d !

    $ {}                      // Separate with whitespace to avoid interpolation!
`
`gimy`                        // flags go here

/*
returns the RegExp
/(foo*(?:bar|baz)quux?)\s\t\r\n\[\]\\\/\`Hello[ ]World!${}/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]
的作用。

请注意,与正则表达式文字不同,Javascript 解析器不会缓存它,因此如果您重用它,请将生成的正则表达式保存在变量中。


0
投票

我建议你在带有正则表达式的行上方放置一个正则注释,以便对其进行解释。

你会有更多的自由。


0
投票

您可以使用 verbose-regexp 包。

import { rx } from 'verbose-regexp'

const dateTime = rx`
 (\d{4}) // year
 -       // separator
 (\d{2}) // month
`

// returns RegExp /(\d{4})-(\d{2})/

0
投票

Perl 的

/x
标志(允许空格和#comments)现在已经进入 Javascript 语言提案过程的第 3(共 4)阶段。

babeljs
有一个插件来模拟它。

© www.soinside.com 2019 - 2024. All rights reserved.