代码之家  ›  专栏  ›  技术社区  ›  observer Darrel Miller

正则表达式匹配使用各种正则表达式引擎

  •  0
  • observer Darrel Miller  · 技术社区  · 5 年前

    我想用 regular expression 然后访问带圆括号的子字符串:

    var myString = "something format_abc"; // I want "abc"
    
    var arr = /(?:^|\s)format_(.*?)(?:\s|$)/.exec(myString);
    
    console.log(arr);     // Prints: [" format_abc", "abc"] .. so far so good.
    console.log(arr[1]);  // Prints: undefined  (???)
    console.log(arr[0]);  // Prints: format_undefined (!!!)
    


    我发现上面的正则表达式代码没有任何问题:我测试的实际字符串是:

    "date format_%A"
    

    报告“%A”未定义似乎是一种非常奇怪的行为,但它与此问题没有直接关系,因此我打开了一个新问题, Why is a matched substring returning "undefined" in JavaScript? .


    问题是 console.log printf 语句,因为我记录的字符串( "%A" )有一个特殊的值,它试图找到下一个参数的值。

    0 回复  |  直到 9 年前
        1
  •  1775
  •   Christian C. Salvadó    6 年前

    您可以这样访问捕获组:

    var myString = "something format_abc";
    var myRegexp = /(?:^|\s)format_(.*?)(?:\s|$)/g;
    var match = myRegexp.exec(myString);
    console.log(match[1]); // abc

    如果有多个匹配项,您可以对其进行迭代:

    var myString = "something format_abc";
    var myRegexp = /(?:^|\s)format_(.*?)(?:\s|$)/g;
    match = myRegexp.exec(myString);
    while (match != null) {
      // matched text: match[0]
      // match start: match.index
      // capturing group n: match[n]
      console.log(match[0])
      match = myRegexp.exec(myString);
    }

    正如您所见,迭代多个匹配项的方法不是很直观。这导致了 String.prototype.matchAll 方法。这种新方法有望在未来几年内推出 ECMAScript 2020 specification . 它为我们提供了一个干净的API并解决了多个问题。它已经开始登陆主流浏览器和JS引擎 Chrome 73+ / Node 12+ 和Firefox 67+。

    const string = "something format_abc";
    const regexp = /(?:^|\s)format_(.*?)(?:\s|$)/g;
    const matches = string.matchAll(regexp);
        
    for (const match of matches) {
      console.log(match);
      console.log(match.index)
    }

    当它返回一个迭代器时,我们可以说它是懒惰的,这在处理大量捕获组或非常大的字符串时非常有用。但如果需要,可以使用 扩展语法 Array.from 方法:

    function getFirstGroup(regexp, str) {
      const array = [...str.matchAll(regexp)];
      return array.map(m => m[1]);
    }
    
    // or:
    function getFirstGroup(regexp, str) {
      return Array.from(str.matchAll(regexp), m => m[1]);
    }
    

    同时,虽然这个提议得到了更广泛的支持,但您可以使用 official shim package

    此外,该方法的内部工作原理也很简单。使用生成器函数的等效实现如下所示:

    function* matchAll(str, regexp) {
      const flags = regexp.global ? regexp.flags : regexp.flags + "g";
      const re = new RegExp(regexp, flags);
      let match;
      while (match = re.exec(str)) {
        yield match;
      }
    }
    

    lastIndex 进行多重匹配时的属性。

    标志以避免无限循环。

    discussions of the proposal .

        2
  •  192
  •   Blowsie Mathias Bynens    11 年前

    function getMatches(string, regex, index) {
      index || (index = 1); // default to the first capturing group
      var matches = [];
      var match;
      while (match = regex.exec(string)) {
        matches.push(match[index]);
      }
      return matches;
    }
    
    
    // Example :
    var myString = 'something format_abc something format_def something format_ghi';
    var myRegEx = /(?:^|\s)format_(.*?)(?:\s|$)/g;
    
    // Get an array containing the first capturing group for every match
    var matches = getMatches(myString, myRegEx, 1);
    
    // Log results
    document.write(matches.length + ' matches found: ' + JSON.stringify(matches))
    console.log(matches);
        3
  •  62
  •   Michael come lately PhiLho    9 年前

    var myString = "something format_abc";
    var arr = myString.match(/\bformat_(.*?)\b/);
    console.log(arr[0] + " " + arr[1]);

    这个 \b --format_foo/ format_a_b match

        4
  •  34
  •   Sebastien H.    7 年前

    最后但并非最不重要的一点是,我发现一行代码对我来说运行良好(JS ES6):

    let reg = /#([\S]+)/igm; // Get hashtags.
    let string = 'mi alegría es total! ✌🙌\n#fiestasdefindeaño #PadreHijo #buenosmomentos #france #paris';
    
    let matches = (string.match(reg) || []).map(e => e.replace(reg, '$1'));
    console.log(matches);

    ['fiestasdefindeaño', 'PadreHijo', 'buenosmomentos', 'france', 'paris']
    
        5
  •  33
  •   Alexz    12 年前

    关于上面的多匹配圆括号示例,我在没有得到我想要的答案后在这里寻找答案:

    var matches = mystring.match(/(?:neededToMatchButNotWantedInResult)(matchWanted)/igm);
    

    在看了上面用while和.push()进行的稍微复杂的函数调用之后,我突然意识到用while和.push()可以非常优雅地解决这个问题mystring.replace()相反(替换不是重点,甚至还没有完成,第二个参数的干净的、内置的递归函数调用选项是!):

    var yourstring = 'something format_abc something format_def something format_ghi';
    
    var matches = [];
    yourstring.replace(/format_([^\s]+)/igm, function(m, p1){ matches.push(p1); } );
    

    在这之后,我想我再也不会对任何东西使用.match()。

        6
  •  25
  •   Wiktor Stribiżew    7 年前

    String#matchAll (参见 Stage 3 Draft / December 7, 2018 proposal

    matchAll 可用时,可以避免 while exec 具有 /g ... 相反,使用 火柴 for...of , array spread Array.from() 构造

    此方法产生与 Regex.Matches 在C#, re.finditer preg_match_all 在PHP中。

    查看JS演示(在googlechrome73.0.3683.67(官方版本)中测试,beta(64位)):

    var myString = "key1:value1, key2-value2!!@key3=value3";
    var matches = myString.matchAll(/(\w+)[:=-](\w+)/g);
    console.log([...matches]); // All match with capturing group values

    这个 console.log([...matches])

    enter image description here

    您还可以使用

    let matchData = "key1:value1, key2-value2!!@key3=value3".matchAll(/(\w+)[:=-](\w+)/g)
    var matches = [...matchData]; // Note matchAll result is not re-iterable
    
    console.log(Array.from(matches, m => m[0])); // All match (Group 0) values
    // => [ "key1:value1", "key2-value2", "key3=value3" ]
    console.log(Array.from(matches, m => m[1])); // All match (Group 1) values
    // => [ "key1", "key2", "key3" ]

    注意 browser compatibility 细节。

        7
  •  20
  •   Daniel Hallgren    8 年前

    • 匹配 指示对字符串运行RegEx模式的结果,如下所示: someString.match(regexPattern) .
    • 匹配的模式 比赛 数组。这些都是输入字符串中模式的实例。
    • 指示要捕获的所有组,在RegEx模式中定义。(括号内的图案如下: /format_(.*?)/g ,在哪里 (.*?) 是一个匹配的组。)这些位于 匹配的模式

    说明

    才能进入 匹配的组 匹配的模式 ,您需要一个函数或类似的东西来迭代 比赛 . 有很多方法可以做到这一点,正如许多其他答案所示。大多数其他答案都使用while循环来迭代所有的答案 匹配的模式 但我想我们都知道这种方法的潜在危险。有必要与 new RegExp() .exec() 方法的行为类似于 it stops every time there is a match ,但保持 .lastIndex .exec()

    代码示例

    下面是一个函数示例 searchString Array 匹配的模式 ,每个 match 带着所有的 . 我没有使用while循环,而是提供了使用 Array.prototype.map() 功能以及一个更有效的方式使用平原 for -循环。

    简洁的版本(更少的代码,更多的语法糖)

    因为它们基本上实现了 forEach 对于 -循环。

    // Concise ES6/ES2015 syntax
    const searchString = 
        (string, pattern) => 
            string
            .match(new RegExp(pattern.source, pattern.flags))
            .map(match => 
                new RegExp(pattern.source, pattern.flags)
                .exec(match));
    
    // Or if you will, with ES5 syntax
    function searchString(string, pattern) {
        return string
            .match(new RegExp(pattern.source, pattern.flags))
            .map(match =>
                new RegExp(pattern.source, pattern.flags)
                .exec(match));
    }
    
    let string = "something format_abc",
        pattern = /(?:^|\s)format_(.*?)(?:\s|$)/;
    
    let result = searchString(string, pattern);
    // [[" format_abc", "abc"], null]
    // The trailing `null` disappears if you add the `global` flag
    

    性能版本(更多的代码,更少的语法糖)

    // Performant ES6/ES2015 syntax
    const searchString = (string, pattern) => {
        let result = [];
    
        const matches = string.match(new RegExp(pattern.source, pattern.flags));
    
        for (let i = 0; i < matches.length; i++) {
            result.push(new RegExp(pattern.source, pattern.flags).exec(matches[i]));
        }
    
        return result;
    };
    
    // Same thing, but with ES5 syntax
    function searchString(string, pattern) {
        var result = [];
    
        var matches = string.match(new RegExp(pattern.source, pattern.flags));
    
        for (var i = 0; i < matches.length; i++) {
            result.push(new RegExp(pattern.source, pattern.flags).exec(matches[i]));
        }
    
        return result;
    }
    
    let string = "something format_abc",
        pattern = /(?:^|\s)format_(.*?)(?:\s|$)/;
    
    let result = searchString(string, pattern);
    // [[" format_abc", "abc"], null]
    // The trailing `null` disappears if you add the `global` flag
    

    我还没有将这些替代方案与前面提到的其他答案进行比较,但我怀疑这种方法的性能和故障安全性不如其他方法。

        8
  •  17
  •   Jonathan Lonowski    17 年前

    你的语法可能不是最好的。FF/Gecko将RegExp定义为函数的扩展。
    (FF2飞到了 typeof(/pattern/) == 'function' )

    相反,请使用其他人之前提到的任何一种方法: RegExp#exec String#match

    var regex = /(?:^|\s)format_(.*?)(?:\s|$)/;
    var input = "something format_abc";
    
    regex(input);        //=> [" format_abc", "abc"]
    regex.exec(input);   //=> [" format_abc", "abc"]
    input.match(regex);  //=> [" format_abc", "abc"]
    
        9
  •  16
  •   Andre Carneiro    9 年前

    exec 方法!可以直接在字符串上使用“match”方法。别忘了括号。

    var str = "This is cool";
    var matches = str.match(/(This is)( cool)$/);
    console.log( JSON.stringify(matches) ); // will print ["This is cool","This is"," cool"] or something like that...
    

    位置0有一个包含所有结果的字符串。位置1的第一个匹配用括号表示,位置2的第二个匹配用括号分隔。嵌套括号很棘手,所以要小心!

        10
  •  8
  •   Nabil Kadimi    12 年前

    只有一对圆括号才实用的一行:

    while ( ( match = myRegex.exec( myStr ) ) && matches.push( match[1] ) ) {};
    
        11
  •  8
  •   David Cheung    7 年前

    String.match() 使用命名组,可以使正则表达式更明确地说明它试图做什么。

    const url =
      'https://stackoverflow.com/questions/432493/how-do-you-access-the-matched-groups-in-a-javascript-regular-expression?some=parameter';
    const regex = /(?<protocol>https?):\/\/(?<hostname>[\w-\.]*)\/(?<pathname>[\w-\./]+)\??(?<querystring>.*?)?$/;
    const { groups: segments } = url.match(regex);
    console.log(segments);
    

        12
  •  7
  •   eyelidlessness    17 年前

    使用您的代码:

    console.log(arr[1]);  // prints: abc
    console.log(arr[0]);  // prints:  format_abc
    

        13
  •  6
  •   Nisse Engström sting_roc    9 年前

    function getMatches(string, regex, index) {
      index || (index = 1); // default to the first capturing group
      var matches = [];
      var match;
      while (match = regex.exec(string)) {
        matches.push(match[index]);
      }
      return matches;
    }
    
    
    // Example :
    var myString = 'Rs.200 is Debited to A/c ...2031 on 02-12-14 20:05:49 (Clear Bal Rs.66248.77) AT ATM. TollFree 1800223344 18001024455 (6am-10pm)';
    var myRegEx = /clear bal.+?(\d+\.?\d{2})/gi;
    
    // Get an array containing the first capturing group for every match
    var matches = getMatches(myString, myRegEx, 1);
    
    // Log results
    document.write(matches.length + ' matches found: ' + JSON.stringify(matches))
    console.log(matches);

    function getMatches(string, regex, index) {
      index || (index = 1); // default to the first capturing group
      var matches = [];
      var match;
      while (match = regex.exec(string)) {
        matches.push(match[index]);
      }
      return matches;
    }
    
    
    // Example :
    var myString = 'something format_abc something format_def something format_ghi';
    var myRegEx = /(?:^|\s)format_(.*?)(?:\s|$)/g;
    
    // Get an array containing the first capturing group for every match
    var matches = getMatches(myString, myRegEx, 1);
    
    // Log results
    document.write(matches.length + ' matches found: ' + JSON.stringify(matches))
    console.log(matches);
        14
  •  3
  •   Community Mohan Dere    9 年前

    你的代码适用于我(Mac上的FF3),即使我同意 PhiLo 正则表达式应该是:

    /\bformat_(.*?)\b/
    

        15
  •  2
  •   Pawel Kwiecien    11 年前
    /*Regex function for extracting object from "window.location.search" string.
     */
    
    var search = "?a=3&b=4&c=7"; // Example search string
    
    var getSearchObj = function (searchString) {
    
        var match, key, value, obj = {};
        var pattern = /(\w+)=(\w+)/g;
        var search = searchString.substr(1); // Remove '?'
    
        while (match = pattern.exec(search)) {
            obj[match[0].split('=')[0]] = match[0].split('=')[1];
        }
    
        return obj;
    
    };
    
    console.log(getSearchObj(search));
    
        16
  •  2
  •   ccpizza    7 年前

    您实际上不需要显式循环来解析多个匹配项,而是将替换函数作为第二个参数传递,如中所述: String.prototype.replace(regex, func) :

    var str = "Our chief weapon is {1}, {0} and {2}!"; 
    var params= ['surprise', 'fear', 'ruthless efficiency'];
    var patt = /{([^}]+)}/g;
    
    str=str.replace(patt, function(m0, m1, position){return params[parseInt(m1)];});
    
    document.write(str);

    这个 m0 {0} , {1} 等等。 m1 表示第一个匹配组,即在正则表达式中用括号括起来的部分 0 position 是字符串中的起始索引,在本例中,在该字符串中发现匹配组未使用。

        17
  •  1
  •   Md. A. Barik    7 年前

    /([a-z])\1/
    

        18
  •  1
  •   Caio Santos    6 年前

    单线解决方案:

    const matches = (text,regex) => [...text.matchAll(regex)].map(([match])=>match)
    

    matches("something format_abc", /(?:^|\s)format_(.*?)(?:\s|$)/g)
    

    结果:

    [" format_abc"]
    
        19
  •  1
  •   ßãlãjî    6 年前

    只需使用RegExp.$1…$n组 如:

    1.匹配第一组RegExp.$1

    如果在regex likey中使用3 group(注意在字符串。匹配(正则表达式)

    正则表达式$1正则表达式$2正则表达式$3

     var str = "The rain in ${india} stays safe"; 
      var res = str.match(/\${(.*?)\}/ig);
      //i used only one group in above example so RegExp.$1
    console.log(RegExp.$1)

    //easiest way is use RegExp.$1 1st group in regex and 2nd grounp like
     //RegExp.$2 if exist use after match
    
    var regex=/\${(.*?)\}/ig;
    var str = "The rain in ${SPAIN} stays ${mainly} in the plain"; 
      var res = str.match(regex);
    for (const match of res) {
      var res = match.match(regex);
      console.log(match);
      console.log(RegExp.$1)
     
    }
        20
  •  0
  •   Kamil Kiełczewski    6 年前

    let m=[], s = "something format_abc  format_def  format_ghi";
    
    s.replace(/(?:^|\s)format_(.*?)(?:\s|$)/g, (x,y)=> m.push(y));
    
    console.log(m);
        21
  •  0
  •   Delcon    6 年前

    你和我一样,希望regex能返回这样的对象:

    {
        match: '...',
        matchAtIndex: 0,
        capturedGroups: [ '...', '...' ]
    }
    

    然后从下面剪掉函数

    /**
     * @param {string | number} input
     *          The input string to match
     * @param {regex | string}  expression
     *          Regular expression 
     * @param {string} flags
     *          Optional Flags
     * 
     * @returns {array}
     * [{
        match: '...',
        matchAtIndex: 0,
        capturedGroups: [ '...', '...' ]
      }]     
     */
    function regexMatch(input, expression, flags = "g") {
      let regex = expression instanceof RegExp ? expression : new RegExp(expression, flags)
      let matches = input.matchAll(regex)
      matches = [...matches]
      return matches.map(item => {
        return {
          match: item[0],
          matchAtIndex: item.index,
          capturedGroups: item.length > 1 ? item.slice(1) : undefined
        }
      })
    }
    
    let input = "key1:value1, key2:value2 "
    let regex = /(\w+):(\w+)/g
    
    let matches = regexMatch(input, regex)
    
    console.log(matches)
        22
  •  0
  •   MSS    5 年前

    正如@cms在ECMAScript(ECMA-262)中所说的,您可以使用 matchAll [... ] (spread操作符)它转换成数组。(这个正则表达式提取文件名的url)

    let text = `<a href="http://myhost.com/myfile_01.mp4">File1</a> <a href="http://myhost.com/myfile_02.mp4">File2</a>`;
    
    let fileUrls = [...text.matchAll(/href="(http\:\/\/[^"]+\.\w{3})\"/g)].map(r => r[1]);
    
    console.log(fileUrls);
    推荐文章