如何检查Regex是否在某个索引之前匹配而不搜索整个字符串,或者regex是否与JavaScript中的索引匹配?

时间:2017-11-03 00:02:00

标签: javascript node.js regex

我有一个案例,我使用正则表达式检查字符串是否匹配,在开始索引之后和结束之前。

要设置起点,可以在运行new Regexp()之前创建exec()并设置其索引。

但是,我无法找到限制其搜索深度的方法。一个"显而易见的"解决方案可能是使用substring()来获取无法通过点搜索的字符串,但这会对性能产生巨大的负面影响。设置包含substring()的正则表达式搜索深度限制的任何解决方案都不行,并且IMO令人尴尬地效率低下,所以请不要发布它们。

我可以想象解决这个问题的三种方式是:

  1. 如果有某种方法可以设置限制,例如myRegex.exec(string, stopIndex)myString.length = temporaryFakeLimit; //do regex, reset length。这些都不起作用或存在。

  2. 如果有某种方法可以检查字符串中索引的正则表达式匹配,即myRegex.testAt(myString, indexToCheck),我可以自己遍历字符串,检查匹配。

  3. 如果存在正则表达式的非本机实现,则可以执行上述任一操作。

  4. 到目前为止,我还没有找到一个好的解决方案。

    如何在某个索引之前检查正则表达式是否在字符串中匹配,而不检索整个字符串?

    <小时/>

    编辑(不是OP)

    进一步添加:

      

    如果它没有找到匹配项,并且我只在100000个字符文本上查找100个字符,这就是一个问题。

    如何使用RegEx搜索给定字符串的一部分。字符串的这一部分应由表示起始索引和结束索引的参数确定。

    参数示例

    var str = `Check enhancement bonus fear effect fly initiative check panicked points of damage rounding stunned touch attack unarmed strike. Aquatic subtype attack of opportunity catching on fire charm conjuration deafened evasion evil domain fast healing favored class fire domain gaseous form healing subschool incorporeal melee weapon multiplying skill points stunned summoning subschool take 10 turn. Adjacent class concentrate on a spell energy drained infection intelligence invisible law domain mundane nonlethal damage small.`;
    
    var rgx = /\d\d/;
    
    var start = 300;
    
    var end = 500;
    

    结果应为:

      

    10

4 个答案:

答案 0 :(得分:1)

我不确定我是否理解您的要求,但我认为您可以使用(^.{0,4})(the actual regex)(.*)这样的内容,并通过4更改[max size] - [actual regex length]来调整长度。

我不知道如何在JavaScript中实现正则表达式引擎,但我认为通过使用类似的东西,引擎不会处理整个字符串。

上面的例子将在字符串的开头开始搜索。要从偏移量开始,您可以使用以下内容:

(^.{5}.{0,4})(the actual regex)(.*)其中5是偏移量。

答案 1 :(得分:0)

您可以使用for循环和break

let str = "test string";

let match = "string";

let limit = 4;

let res = "";

for (let i = 0; i < str.length; i++) {
  console.log(i, i < limit);
  if (i >= limit - 1) {
    if (!res) {
      res = null;
    }
    break;
  };
  // alternatively, using `RegExp`
  // new RegExp(str[i], "i").test(match[i])
  if (str[i] === match[i]) { 
    res += str[i]
  }
}

console.log(res);

答案 2 :(得分:0)

编辑:忽略以下内容,这个问题的真正答案是substr在js中不像我想象的那样工作。在本机浏览器代码中,字符串是不可变的,因此当调用substr()时,它只能使用新的start和length属性引用原始字符串。它超级高效。

老答案:

我已经设法找到了解决方案,虽然它很难看。我们的想法是使用匹配您正在寻找的东西或任何东西的正则表达式。因为如果它与你想要的不匹配,它将匹配任何东西,它一次移动一个char。使用捕获组,您可以检查它是否与您想要的东西或虚拟匹配相匹配。

它的代码是这样的:

var stringToSearch = "hey hi ho here we go, woop de do an2 for you, lalala lelele lolol goop da woop ba bee";

var whatIWant = "a.+[1-3]";
var anyChar = ".|\n"

var myRegex = new RegExp("("+whatIWant+")|"+anyChar, 'g');


function boundedRegexSearch(searchMe, regex, start, end) {
  regex.lastIndex = start; //start search index
  
  var keepSearching = true;
  while(keepSearching) {
    var result = regex.exec(searchMe);
    var whatImSearchingFor = result[1];
  
    if(whatImSearchingFor !== undefined)
      return whatImSearchingFor;
   
    keepSearching = regex.lastIndex < end;
  }
}


//can not match anything from index 0 to 8, returns undefined
console.log(boundedRegexSearch(stringToSearch, myRegex, 0, 8));

//can match "an2" at index 36
console.log(boundedRegexSearch(stringToSearch, myRegex, 20, 40));

答案 3 :(得分:0)

OP问题

  

如何在某个索引之前检查正则表达式是否在字符串中匹配,而不检索整个字符串?

评论已添加至问题

  

如果找不到匹配项,并且我只在100000字符文本上查找100个字符,那就是一个问题。这不是关于预期的输出,而是关于一个似乎不存在的功能。

考虑到管理不善的问题中的这两个要求,我们应该做到以下几点:

  • 选择4个参数:字符串str,RegEx tgt,起始索引ptA和结束索引ptZ

  • 使用slice(ptA, (ptZ+1))提取新字符串。 ptZ+1是因为ptZ是独占的。

  • 然后使用match()在新字符串上使用tgt

由于OP强调了性能,这里是OP答案与 jsPerf 的答案之间的测试。

演示

const str = `Anything suspicious? Well... then should we go? Any uh... Cartel news these days? Seems like I'm always reading something or other in the paper. I don't want to talk about it. To you or anyone else. I'm done explaining myself. Gus is dead. We've got work to do. `;

let tgt = /Cartel/;

function searchIndexRange(str, rgx, ptA, ptZ) {
  const frag = str.slice(ptA, (ptZ + 1));
  let exists = frag.match(rgx);
  if (exists !== -1) {
    return exists;
  } else return false;
}

// First call returns null 
// Second call returns the search key "Cartel"

let res = JSON.stringify(searchIndexRange(str, tgt, 0, 1));
console.log(res);

res = JSON.stringify(searchIndexRange(str, tgt, 0, 100));
console.log(res);