代码之家  ›  专栏  ›  技术社区  ›  Nik Sumeiko

如何在JavaScript中将一个长正则表达式拆分为多行?

  •  188
  • Nik Sumeiko  · 技术社区  · 13 年前

    我有一个很长的正则表达式,我希望在JavaScript代码中将其拆分为多行,以根据JSLint规则保持每行长度为80个字符。我认为它只是更适合阅读。 以下是图案示例:

    var pattern = /^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
    
    11 回复  |  直到 13 年前
        1
  •  158
  •   Géry Ogam    3 年前

    扩展@KooiInc的答案,您可以使用 source 的财产 RegExp 对象

    示例:

    var urlRegex = new RegExp(
      /(?:(?:(https?|ftp):)?\/\/)/.source       // protocol
      + /(?:([^:\n\r]+):([^@\n\r]+)@)?/.source  // user:pass
      + /(?:(?:www.)?([^/\n\r]+))/.source       // domain
      + /(\/[^?\n\r]+)?/.source                 // request
      + /(\?[^#\n\r]*)?/.source                 // query
      + /(#?[^\n\r]*)?/.source                  // anchor
    );
    

    或者如果你想避免重复 .source 属性,可以使用 Array.map() 功能:

    var urlRegex = new RegExp([
      /(?:(?:(https?|ftp):)?\/\/)/,     // protocol
      /(?:([^:\n\r]+):([^@\n\r]+)@)?/,  // user:pass
      /(?:(?:www.)?([^/\n\r]+))/,       // domain
      /(\/[^?\n\r]+)?/,                 // request
      /(\?[^#\n\r]*)?/,                 // query
      /(#?[^\n\r]*)?/,                  // anchor
    ].map(function (r) { return r.source; }).join(''));
    

    在ES6中,映射函数可以简化为: .map(r => r.source)

        2
  •  140
  •   KooiInc    3 年前

    [ 编辑2022/08 ]创建了一个小 github repository 创建带有空格、注释和模板的正则表达式。


    您可以将其转换为字符串,并通过调用 new RegExp() 以下为:

    var myRE = new RegExp (['^(([^<>()[\]\\.,;:\\s@\"]+(\\.[^<>(),[\]\\.,;:\\s@\"]+)*)',
                            '|(\\".+\\"))@((\\[[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.',
                            '[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\\.)+',
                            '[a-zA-Z]{2,}))$'].join(''));
    

    注意事项:

    1. 当转换 表达式文字 对于字符串,您需要转义所有反斜杠,因为在计算 字符串文字 (更多详细信息,请参阅Kayo的评论。)

    2. RegExp 接受修饰符作为第二个参数

      /regex/g => new RegExp('regex', 'g')

    [ 添加ES20xx (标记模板)]

    在ES20xx中,您可以使用 tagged templates 。请参阅片段。

    注:

    • 这里的缺点是不能在正则表达式字符串中使用纯空白(总是使用 \s , \s+ , \s{1,x} , \t , \n 等等)。

    (() => {
      const createRegExp = (str, opts) => 
        new RegExp(str.raw[0].replace(/\s/gm, ""), opts || "");
      const yourRE = createRegExp`
        ^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|
        (\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|
        (([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$`;
      console.log(yourRE);
      const anotherLongRE = createRegExp`
        (\byyyy\b)|(\bm\b)|(\bd\b)|(\bh\b)|(\bmi\b)|(\bs\b)|(\bms\b)|
        (\bwd\b)|(\bmm\b)|(\bdd\b)|(\bhh\b)|(\bMI\b)|(\bS\b)|(\bMS\b)|
        (\bM\b)|(\bMM\b)|(\bdow\b)|(\bDOW\b)
        ${"gi"}`;
      console.log(anotherLongRE);
    })();
        3
  •  33
  •   Riccardo Galli    11 年前

    在中使用字符串 new RegExp 很尴尬,因为您必须转义所有的反斜杠。您可以编写较小的正则表达式并将它们连接起来。

    让我们拆分这个正则表达式

    /^foo(.*)\bar$/
    

    我们稍后将使用一个函数使事物更加美丽

    function multilineRegExp(regs, options) {
        return new RegExp(regs.map(
            function(reg){ return reg.source; }
        ).join(''), options);
    }
    

    现在让我们摇滚

    var r = multilineRegExp([
         /^foo/,  // we can add comments too
         /(.*)/,
         /\bar$/
    ]);
    

    由于这是有成本的,所以尝试只构建一次真正的正则表达式,然后使用它。

        4
  •  17
  •   Hashbrown    6 年前

    感谢神奇的世界 template literals 你现在可以写大的,多行,评论良好, 甚至在语义上嵌套 ES6中的正则表达式。

    //build regexes without worrying about
    // - double-backslashing
    // - adding whitespace for readability
    // - adding in comments
    let clean = (piece) => (piece
        .replace(/((^|\n)(?:[^\/\\]|\/[^*\/]|\\.)*?)\s*\/\*(?:[^*]|\*[^\/])*(\*\/|)/g, '$1')
        .replace(/((^|\n)(?:[^\/\\]|\/[^\/]|\\.)*?)\s*\/\/[^\n]*/g, '$1')
        .replace(/\n\s*/g, '')
    );
    window.regex = ({raw}, ...interpolations) => (
        new RegExp(interpolations.reduce(
            (regex, insert, index) => (regex + insert + clean(raw[index + 1])),
            clean(raw[0])
        ))
    );
    

    使用它,您现在可以像这样编写正则表达式:

    let re = regex`I'm a special regex{3} //with a comment!`;
    

    输出

    /I'm a special regex{3}/
    

    Or what about multiline?

    '123hello'
        .match(regex`
            //so this is a regex
    
            //here I am matching some numbers
            (\d+)
    
            //Oh! See how I didn't need to double backslash that \d?
            ([a-z]{1,3}) /*note to self, this is group #2*/
        `)
        [2]
    

    输出 hel 整洁的
    “如果我真的需要搜索一个换行符怎么办?”,然后使用 \n 愚蠢的
    在我的Firefox和Chrome上工作。


    好吧,“来点更复杂的吧?”
    当然 here's a piece of an object destructuring JS parser I was working on 以下为:

    regex`^\s*
        (
            //closing the object
            (\})|
    
            //starting from open or comma you can...
            (?:[,{]\s*)(?:
                //have a rest operator
                (\.\.\.)
                |
                //have a property key
                (
                    //a non-negative integer
                    \b\d+\b
                    |
                    //any unencapsulated string of the following
                    \b[A-Za-z$_][\w$]*\b
                    |
                    //a quoted string
                    //this is #5!
                    ("|')(?:
                        //that contains any non-escape, non-quote character
                        (?!\5|\\).
                        |
                        //or any escape sequence
                        (?:\\.)
                    //finished by the quote
                    )*\5
                )
                //after a property key, we can go inside
                \s*(:|)
          |
          \s*(?={)
            )
        )
        ((?:
            //after closing we expect either
            // - the parent's comma/close,
            // - or the end of the string
            \s*(?:[,}\]=]|$)
            |
            //after the rest operator we expect the close
            \s*\}
            |
            //after diving into a key we expect that object to open
            \s*[{[:]
            |
            //otherwise we saw only a key, we now expect a comma or close
            \s*[,}{]
        ).*)
    $`
    

    它输出 /^\s*((\})|(?:[,{]\s*)(?:(\.\.\.)|(\b\d+\b|\b[A-Za-z$_][\w$]*\b|("|')(?:(?!\5|\\).|(?:\\.))*\5)\s*(:|)|\s*(?={)))((?:\s*(?:[,}\]=]|$)|\s*\}|\s*[{[:]|\s*[,}{]).*)$/

    用一个小演示来运行它?

    let input = '{why, hello, there, "you   huge \\"", 17, {big,smelly}}';
    for (
        let parsed;
        parsed = input.match(r);
        input = parsed[parsed.length - 1]
    ) console.log(parsed[1]);
    

    成功输出

    {why
    , hello
    , there
    , "you   huge \""
    , 17
    ,
    {big
    ,smelly
    }
    }
    

    请注意已成功捕获带引号的字符串。
    我在Chrome和Firefox上测试了它,效果不错!

    如果 curious you can checkout what I was doing its demonstration
    尽管它只适用于Chrome,因为Firefox不支持反向引用或命名组。请注意,这个答案中给出的例子实际上是一个中性版本,可能很容易被欺骗接受无效字符串。

        5
  •  11
  •   Jamesfo    7 年前

    这里有很好的答案,但为了完整起见,有人应该提到Javascript的核心特性继承 prototype chain 。这样的东西说明了这个想法:

    RegExp.prototype.append = function(re) {
      return new RegExp(this.source + re.source, this.flags);
    };
    
    let regex = /[a-z]/g
    .append(/[A-Z]/)
    .append(/[0-9]/);
    
    console.log(regex); //=> /[a-z][A-Z][0-9]/g
        6
  •  6
  •   Anvesh Reddy    9 年前

    上面的正则表达式缺少一些无法正常工作的黑斜杠。所以,我编辑了正则表达式。请考虑这个正则表达式,它可以99.99%地用于电子邮件验证。

    let EMAIL_REGEXP = 
    new RegExp (['^(([^<>()[\\]\\\.,;:\\s@\"]+(\\.[^<>()\\[\\]\\\.,;:\\s@\"]+)*)',
                        '|(".+"))@((\\[[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.',
                        '[0-9]{1,3}\])|(([a-zA-Z\\-0-9]+\\.)+',
                        '[a-zA-Z]{2,}))$'].join(''));
    
        7
  •  2
  •   andreasonny83    8 年前

    避开阵列 join ,也可以使用以下语法:

    var pattern = new RegExp('^(([^<>()[\]\\.,;:\s@\"]+' +
      '(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@' +
      '((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|' +
      '(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$');
    
        8
  •  2
  •   Mubeena    7 年前

    您可以简单地使用字符串操作。

    var pattenString = "^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|"+
    "(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|"+
    "(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$";
    var patten = new RegExp(pattenString);
    
        9
  •  2
  •   Scindix    6 年前

    我试图通过封装所有内容并实现对拆分捕获组和字符集的支持来改进korun的答案,使这种方法更加通用。

    要使用此代码段,您需要调用variadic函数 combineRegex 其参数是需要组合的正则表达式对象。它的实现可以在底部找到。

    捕获组不能以这种方式直接拆分,因为它只会留下一个括号。您的浏览器将出现异常而失败。

    相反,我只是在数组中传递捕获组的内容。括号是在以下情况下自动添加的 组合Regex 遇到数组。

    此外,量词需要跟在某物后面。如果由于某种原因,正则表达式需要在量词前面拆分,则需要添加一对括号。这些将自动删除。重点是,一个空的捕获组是非常无用的,这样量词就有了可参考的东西( /(?:abc)/ 变成 [/()?:abc/] )。

    最好用一个简单的例子来解释这一点:

    var regex = /abcd(efghi)+jkl/;
    

    将变成:

    var regex = combineRegex(
        /ab/,
        /cd/,
        [
            /ef/,
            /ghi/
        ],
        /()+jkl/    // Note the added '()' in front of '+'
    );
    

    如果必须拆分角色集,则可以使用对象( {"":[regex1, regex2, ...]} )而不是数组( [regex1, regex2, ...] )。只要对象只包含一个键,键的内容就可以是任何内容。请注意,而不是 () 你必须使用 ] 如果第一个字符可以被解释为量词,则作为伪开头。即。 /[+?]/ 变成 {"":[/]+?/]}

    以下是片段和更完整的示例:

    function combineRegexStr(dummy, ...regex)
    {
        return regex.map(r => {
            if(Array.isArray(r))
                return "("+combineRegexStr(dummy, ...r).replace(dummy, "")+")";
            else if(Object.getPrototypeOf(r) === Object.getPrototypeOf({}))
                return "["+combineRegexStr(/^\]/, ...(Object.entries(r)[0][1]))+"]";
            else 
                return r.source.replace(dummy, "");
        }).join("");
    }
    function combineRegex(...regex)
    {
        return new RegExp(combineRegexStr(/^\(\)/, ...regex));
    }
    
    //Usage:
    //Original:
    console.log(/abcd(?:ef[+A-Z0-9]gh)+$/.source);
    //Same as:
    console.log(
      combineRegex(
        /ab/,
        /cd/,
        [
          /()?:ef/,
          {"": [/]+A-Z/, /0-9/]},
          /gh/
        ],
        /()+$/
      ).source
    );
        10
  •  1
  •   Bart Kiers    8 年前

    就我个人而言,我会选择一个不那么复杂的正则表达式:

    /\S+@\S+\.\S+/
    

    当然,少一点 精确的 比你目前的模式,但你试图实现什么?您是在试图捕捉用户可能输入的意外错误,还是担心用户可能试图输入无效地址?如果是第一种,我会选择更简单的模式。如果是后者,通过回复发送到该地址的电子邮件进行一些验证可能是更好的选择。

    然而,如果你想使用当前的模式,通过从更小的子模式构建它(IMO)会更容易阅读(和维护!),如下所示:

    var box1 = "([^<>()[\]\\\\.,;:\s@\"]+(\\.[^<>()[\\]\\\\.,;:\s@\"]+)*)";
    var box2 = "(\".+\")";
    
    var host1 = "(\\[[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\])";
    var host2 = "(([a-zA-Z\-0-9]+\\.)+[a-zA-Z]{2,})";
    
    var regex = new RegExp("^(" + box1 + "|" + box2 + ")@(" + host1 + "|" + host2 + ")$");
    
        11
  •  1
  •   Nuno Cruces    6 年前

    @哈什布朗很棒 answer 让我走上正轨。这是我的版本,也是受此启发 blog

    function regexp(...args) {
      function cleanup(string) {
        // remove whitespace, single and multi-line comments
        return string.replace(/\s+|\/\/.*|\/\*[\s\S]*?\*\//g, '');
      }
    
      function escape(string) {
        // escape regular expression
        return string.replace(/[-.*+?^${}()|[\]\\]/g, '\\$&');
      }
    
      function create(flags, strings, ...values) {
        let pattern = '';
        for (let i = 0; i < values.length; ++i) {
          pattern += cleanup(strings.raw[i]);  // strings are cleaned up
          pattern += escape(values[i]);        // values are escaped
        }
        pattern += cleanup(strings.raw[values.length]);
        return RegExp(pattern, flags);
      }
    
      if (Array.isArray(args[0])) {
        // used as a template tag (no flags)
        return create('', ...args);
      }
    
      // used as a function (with flags)
      return create.bind(void 0, args[0]);
    }
    

    这样使用:

    regexp('i')`
      //so this is a regex
    
      //here I am matching some numbers
      (\d+)
    
      //Oh! See how I didn't need to double backslash that \d?
      ([a-z]{1,3}) /*note to self, this is group #2*/
    `
    

    创建此 RegExp 对象:

    /(\d+)([a-z]{1,3})/i