【问题标题】:Shortest regular expression match if already part of another match如果已经是另一个匹配的一部分,则最短的正则表达式匹配
【发布时间】:2017-02-19 00:33:10
【问题描述】:

我想从整个文本中重复字符串的长文本中检索最短匹配。但是,在已匹配的文本中找不到匹配项。

这是我所面临问题的简化版本:

  • 代码:"ababc".match(/a.+c/g)
  • 观察结果:["ababc"]
  • 预期结果:["ababc", "abc"]

因此,我想知道是否有比手动编写递归代码在匹配项中搜索更简单的方法来检索子字符串 "abc"

【问题讨论】:

  • 你将如何处理ababcabc,你想要所有可能的排列还是通常的overlapping match handling足够了?
  • 我认为这个问题不能单独用正则表达式解决。正则表达式引擎仅在必要时放弃匹配的字符,以满足模式的其余部分。 “此匹配更短”不是该条件的一部分
  • @SebastianProske 最终目标是找到最短匹配,因此它只需要在您的示例中找到 ["abc", "abc"] - 不需要所有排列。如您链接到的问题的答案之一中所述,修改“lastIndex”属性看起来非常好,因此感谢您的链接。

标签: javascript regex


【解决方案1】:

正如我在评论中提到的,你不能只用正则表达式做你想做的事。

您提供了一个简化的示例,因此我不确定这将带您走多远,但这是我在做您正在寻找的事情的尝试。我偷偷怀疑你的“a”和“c”字符不一样,所以你需要相应地修改它(例如,将它们作为参数传递给函数)。

function getShortestMatch(str) {
  var str = str || ''; 
  var match, 
  index, 
  regex,
  length,
  results = [];
  // iterate along the string one character at a time
  for (index = 0, length = str.length; index < length; index++) {
    // if the current character is 'a' (the beginning part of our substring match)
    if (str[index] === 'a') {
      // create a new regex that first consumes everything up to 
      // the starting character. Then matches for everything from there to 
      // the ending substring char 'c'. It is a lazy match so it will stop 
      // at the first matched ending char 'c'
      regex = new RegExp('^.{' + index + '}(a.+?c)');
      match = str.match(regex);
      // if there is a match, then push to the results array
      if (match && match[1]) {
        results.push(match[1]);
      }
    }
  }
  // sort the results array ascending (shortest first)
  results.sort(function(a,b){
    return a.length - b.length;
  });

  // log all results matched to the console for sake of example
  console.log(results); 

  // return the first (shortest) element
  return results[0];
}

示例

getShortestMatch('ababcabbc');

// output showing all results found (from console.log in the function)
["abc", "abbc", "ababc"]

// return value
"abc"

注意:此函数不会尝试查找“'a' 和 'c' 之间的所有内容”的所有可能匹配项,因为您的问题是关于查找 最短的 em> 一。如果出于某种原因您想要所有可能的匹配项,那么贪婪的 .+ 正则表达式将被混入其中。

【讨论】:

  • 显然有点无关紧要,因为您的输出包含正确的结果 abc... 但只是想知道为什么您认为 ababcabbc 与您的示例不匹配?
  • @RobinMackenzie 是的,如果您要为“ababcabbc”的“a”和“c”之间的所有内容列出所有可能的值,那么是的,完整的字符串将在列表中.我的注释是说明我的函数将不匹配(因为它只对每个索引处的最短值进行惰性匹配)
【解决方案2】:

遍历从每个连续字符开始的子字符串(使用slice),匹配锚定到字符串开头的正则表达式(^),并使用非贪婪匹配(?):

const input = "ababc";
const regexp = /^a.+?c/;

const results = [];
    
for (var i = 0; i < input.length; i++) {
  var match = input.slice(i).match(regexp);
  if (match) results.push(match[0]);
}

console.log("all results are", results);
var shortest = results.sort((a, b) => a.length - b.length)[0];
console.log("shortest result is", shortest);

【讨论】:

    【解决方案3】:

    由于其有效性、简单性和效率,这是我选择的答案:

    let seq = "us warship";
    let source = "The traditional US adversary has also positioned a spy ship off the coast of Delaware and carried out flights near a US Navy warship, concerning American officials.";
    
    let re = new RegExp(`\\b${seq.replace(/\s/g, "\\b.+?\\b")}\\b`, "gi");
    let snippet = null;
    let matches;
    while (matches = re.exec(source)) {
      let match = matches[0];
      if (!snippet || match.length < snippet.length) {
        snippet = match;
      }
      re.lastIndex -= (match.length - 1);
    }
    console.log(snippet); // "US Navy warship"
    

    来源:https://stackoverflow.com/a/8236152/1055499

    【讨论】:

      猜你喜欢
      • 2012-07-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-11-22
      • 1970-01-01
      相关资源
      最近更新 更多