如何在JavaScript regexp中获取子模式的索引?

时间:2013-06-11 08:46:31

标签: javascript regex

我在JavaScript中编写了一个正则表达式,用于在字符串中搜索searchedUrl

var input = '1234 url(  test  ) 5678';
var searchedUrl = 'test';

var regexpStr = "url\\(\\s*"+searchedUrl+"\\s*\\)"; 
var regex = new RegExp(regexpStr , 'i');

var match = input.match(regex);
console.log(match); // return an array

输出:

["url(            test  )", index: 5, input: "1234 url(            test  ) 5678"]

现在我想获得searchedUrl的位置(在上面的示例中,它是test1234 url( test ) 5678的位置。

我该怎么做?

4 个答案:

答案 0 :(得分:2)

据我所知,不可能自动获得子匹配的偏移量,您必须自己使用RegExp的lastIndexindex进行计算。 exec()返回的匹配对象的属性。根据您的使用情况,您必须添加或减去导致您的子匹配的组的长度。但是,这确实意味着您必须将正则表达式的第一部分或最后部分分组,直到您希望找到的模式。

lastIndex似乎只在使用/g/全局标志时发挥作用,它将在整个匹配后记录索引。因此,如果您希望使用lastIndex,则需要从模式的末尾开始向后工作。

有关exec()方法的详细信息,请参阅此处:

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/exec

以下简明扼要地展示了运营中的解决方案:

var str = '---hello123';
var r = /([a-z]+)([0-9]+)/;
var m = r.exec( str );
alert( m.index + m[1].length ); // will give the position of 123

更新

这将适用于您的问题,使用以下内容:

var input = '1234 url(  test  ) 5678';
var searchedUrl = 'test';
var regexpStr = "(url\\(\\s*)("+searchedUrl+")\\s*\\)";
var regex = new RegExp(regexpStr , 'i');
var match = regex.exec(input);

然后要获得子匹配偏移量,您可以使用:

match.index + match[1].length

match[1]现在包含url((加上两个空格),因为括号分组允许我们告诉内部偏移量。

更新2

显然,如果您希望在要查找的实际模式之前在RegExp中设置模式,那么事情会复杂一些。这只是将每个组长度加在一起的简单行为。

var s = '~- [This may or may not be random|it depends on your perspective] -~';
var r = /(\[)([a-z ]+)(\|)([a-z ]+)(\])/i;
var m = r.exec( s );

要获得it depends on your perspective的偏移位置,您将使用:

m.index + m[1].length + m[2].length + m[3].length;

显然,如果你知道RegExp的部分永远不会改变长度,你可以用硬编码数字值替换它们。但是,最好保留上述.length检查,以防您 - 或其他人 - 更改您的表达式匹配的内容。

答案 1 :(得分:2)

JS没有直接的方法来获取子模式/捕获组的索引。但你可以通过一些技巧解决这个问题。例如:

var reStr = "(url\\(\\s*)" + searchedUrl + "\\s*\\)";
var re = new RegExp(reStr, 'i');

var m = re.exec(input);
if(m){
    var index = m.index + m[1].length;
    console.log("url found at " + index);
}

答案 2 :(得分:1)

您不需要索引。

这种情况下,提供更多信息会得到更好的答案。我不能因此而惹你生气;我们鼓励我们创建简单的测试用例并删除不相关的细节。

但是缺少一个重要的项目:你打算用该索引做什么。与此同时,我们都在追逐错误的问题。 : - )

我感觉有些东西不见了;这就是我问你的原因。

正如您在评论中提到的,您希望在输入字符串中找到该网址并以某种方式突出显示该网址,方法可能是将其打包在<b></b>标记中,等等:

'1234 url(  <b>test</b>  ) 5678'

(如果你的意思是“亮点”,请告诉我。)

您可以使用字符索引来执行此操作,但使用正则表达式本身会更容易。

获取索引

但是既然你问过,如果 需要索引,你可以用这样的代码得到它:

var input = '1234 url(  test  ) 5678';
var url = 'test';

var regexpStr = "^(.*url\\(\\s*)"+ url +"\\s*\\)"; 
var regex = new RegExp( regexpStr , 'i' );

var match = input.match( regex );
var start = match[1].length;

这比其他答案中的代码简单一点,但其中任何一个都能同样有效。此方法的工作原理是将正则表达式锚定到包含^的字符串的开头,并将所有字符放在具有()的组中的URL之前。该组字符串match[1]的长度是您的索引。

切片和切块

一旦知道字符串中test的起始索引,就可以使用.slice()或其他字符串方法来剪切字符串并插入标记,可能使用以下代码:

// Wrap url in <b></b> tag by slicing and pasting strings
var output =
    input.slice( 0, start ) +
    '<b>' + url + '</b>' +
    input.slice( start + url.length );

console.log( output );

这肯定会奏效,但它确实是在努力做事。

另外,我遗漏了一些错误处理代码。如果没有匹配的网址怎么办? matchundefinedmatch[1]将失败。但是,不要担心这一点,让我们看看如何在没有任何字符索引的情况下做到这一点。

简单方法

让正则表达式为您完成工作。这就是整个事情:

var input = '1234 url(  test  ) 5678';
var url = 'test';

var regexpStr = "(url\\(\\s*)(" + url + ")(\\s*\\))"; 
var regex = new RegExp( regexpStr , 'i' );

var output = input.replace( regex, "$1<b>$2</b>$3" );

console.log( output );

此代码在正则表达式中有三个组,一个用于捕获URL本身,在URL之前和之后用于捕获其他匹配文本的组,因此我们不会丢失它。然后是一个简单的.replace(),你已经完成了!

您不必担心任何字符串长度或索引。如果找不到URL,代码就会干净利落:它会使输入字符串保持不变。

答案 3 :(得分:-1)

您应该使用.exec,这里有关于mdn website

上子模式匹配的精彩文档