【问题标题】:Regexp to match words two by two (or n by n)正则表达式匹配单词两个两个(或 n 乘 n)
【发布时间】:2016-11-13 10:08:54
【问题描述】:

我正在寻找一个能够将单词 n 匹配 n 的正则表达式。假设n := 2,它会产生:

Lorem ipsum dolor sit amet, consectetur adipiscing elit

Lorem ipsumipsum dolordolor sitsit amet(注意这里的逗号)、consectetur adipiscingadipiscing elit

我曾尝试使用\b 设置单词边界,但无济于事。我真的很想找到一个能够给我n 单词的正则表达式....../\b(\w+)\b(\w+)\b/i 无法削减它,甚至尝试了多种组合。

【问题讨论】:

  • @Biffen 这个问题怎么重复?
  • 这基本上是一个give-me-a-regex“问题”。它们都是(在某种程度上)那个副本的副本。
  • 您需要在单词之间重叠匹配和\W+。检查jsfiddle.net/ncxucvfk
  • @JoColina 我认为您还没有完全理解 \b 的工作原理:(\w+)\b(\w+) 永远无法匹配任何内容,因为根据定义,从来没有单词边界 (@987654337 @) 到单词字符 (\w) 之间。您将不得不考虑空格和标点符号等非单词字符。

标签: javascript regex node.js text nlp


【解决方案1】:

正则表达式并不是您真正需要的,除了将输入拆分为单词。问题是这个问题涉及到匹配 overlapping 子字符串,而 regexp 不是很擅长,尤其是 JavaScript 风格。相反,只需将输入分解为单词,一段快速的 JavaScript 就会生成“n-gram”(这是您的 n-word 组的正确术语)。

const input = "Lorem ipsum dolor sit amet, consectetur adipiscing elit";

// From an array of words, generate n-grams.
function ngrams(words, n) {
  const results = [];

  for (let i = 0; i < words.length - n + 1; i++) 
    results.push(words.slice(i, i + n));

  return results;
}

console.log(ngrams(input.match(/\w+./g), 2));

【讨论】:

    【解决方案2】:

    单词边界\b使用任何字符,它是一个零宽度断言,并且仅断言单词和非单词字符之间的位置, 以及字符串开头和单词 char 之间以及单词 char 和字符串结尾之间。

    您需要使用\s+使用单词之间的空格,并在正向前瞻技术中使用捕获来获得重叠匹配:

    var n = 2;
    var s = "Lorem ipsum dolor sit amet, consectetur adipiscing elit";
    var re = new RegExp("(?=(\\b\\w+(?:\\s+\\w+){" + (n-1) + "}\\b))", "g");
    var res = [], m;
    while ((m=re.exec(s)) !== null) { // Iterating through matches
     if (m.index === re.lastIndex) {  // This is necessary to avoid 
            re.lastIndex++;           // infinite loops with 
     }                                // zero-width matches
     res.push(m[1]);                  // Collecting the results (group 1 values)
    }
    console.log(res);

    最终模式将动态构建,因为您需要将变量传递给正则表达式,因此您需要 RegExp 构造函数表示法。它看起来像

    /(?=(\b\w+(?:\s+\w+){1}\b))/g
    

    它会在字符串中找到所有位置,后面跟着以下顺序:

    • \b - 单词边界
    • \w+ - 1 个或多个单词字符
    • (?:\s+\w+){n} - n 的序列:
      • \s+ - 1 个或多个空格
      • \w+ - 1 个或多个单词字符
    • \b - 词尾边界

    【讨论】:

    • 这看起来有点矫枉过正。
    • 一个可行的、可扩展的解决方案永远不会过大。
    【解决方案3】:

    不是纯粹的正则表达式解决方案,但它有效且易于阅读和理解:

    let input = 'Lorem ipsum dolor sit amet, consectetur adipiscing elit';
    let matches = input.match(/(\w+,? \w+)/g)
        .map(str => str.replace(',', ''));
    
    console.log(matches) // ['Lorem ipsum', 'dolor sit', 'amet consectetur', 'adipiscing elit']
    

    警告:不检查没有匹配项(match() 返回 null)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2022-12-17
      • 1970-01-01
      • 2011-10-15
      • 2017-10-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多