在Javascript中,是否有一种方法可以检索正则表达式match()的结果字符串中(起始)字符位置?
在Javascript中,是否有一种方法可以检索正则表达式match()的结果字符串中(起始)字符位置?
exec
返回一个对象,该对象带有一个 index
属性:
var match = /bar/.exec("foobar");
if (match) {
console.log("match found at " + match.index);
}
对于多个匹配项:
var re = /bar/g,
str = "foobarfoobar";
while ((match = re.exec(str)) != null) {
console.log("match found at " + match.index);
}
// Finds starting and ending positions of quoted text
// in double or single quotes with escape char support like \" \'
var str = "this is a \"quoted\" string as you can 'read'";
var patt = /'((?:\\.|[^'])*)'|"((?:\\.|[^"])*)"/igm;
while (match = patt.exec(str)) {
console.log(match.index + ' ' + patt.lastIndex);
}
match.index + match[0].length
也可以使用。 - Beni Cherniavsky-Paskinmatch.index + match[0].length - 1
吗? - David.slice()
和.substring()
所采用的方式。包含结束位置会比你说的少1个。 (请注意,包容通常意味着匹配中最后一个字符的索引,除非它是空匹配,在这种情况下它是在匹配之前,对于从开头起始的空匹配可能是-1,在字符串外部...) - Beni Cherniavsky-Paskinpatt = /.*/
,它会进入无限循环,我们如何限制它? - abinas patra在现代浏览器中,您可以使用string.matchAll()实现此目的。
相对于RegExp.exec()
,这种方法的好处是它不依赖于正则表达式具有状态,就像@Gumbo答案中所述的那样。
let regexp = /bar/g;
let str = 'foobarfoobar';
let matches = [...str.matchAll(regexp)];
matches.forEach((match) => {
console.log("match found at " + match.index);
});
matchAll
的单行解决方案 let regexp = /bar/g;
let str = 'foobarfoobar';
let matchIndices = Array.from(str.matchAll(regexp)).map(x => x.index);
console.log(matchIndices)```
- Steven Schkolneg
标志的情况下尝试了你的代码,并且出现错误。 - Ooker根据developer.mozilla.org上的文档,String中的.match()
方法会返回一个数组。这个数组会包含一个额外的input属性,它是被解析的原始字符串。此外,它还有一个索引属性,表示匹配在字符串中的从零开始的索引位置。
当处理非全局正则表达式(即您的正则表达式没有在末尾加上g标志)时,.match()
返回的值会有一个index
属性……只需访问即可。
var index = str.match(/regex/).index;
以下是一个演示它正常工作的示例:
var str = 'my string here';
var index = str.match(/here/).index;
console.log(index); // <- 10
我已经成功测试过这个功能,即使是在IE5中也能运行。
search
方法。这只适用于第一个匹配项,但会执行你所描述的操作。例如: search
方法示例:
"How are you?".search(/are/);
// 4
我最近发现了一个很酷的功能,我在控制台上尝试了一下,似乎可以用:
var text = "border-bottom-left-radius";
var newText = text.replace(/-/g,function(match, index){
return " " + index + " ";
});
这句话的意思是:"边框宽度为6,底部内边距为13,左侧内边距为18,圆角半径为默认值"。
因此,这似乎就是您要找的内容。
arguments
中永远是倒数第二个条目是位置,而不是“第二个参数”。函数的参数包括“完整匹配、第一组、第二组,等等,匹配的索引,完整字符串匹配”信息。 - Mike 'Pomax' Kamermans很抱歉,之前的回答(基于exec
)似乎无法处理正则表达式匹配宽度为0的情况。例如(注意:/\b/g
是应该找到所有单词边界的正则表达式):
var re = /\b/g,
str = "hello world";
var guard = 10;
while ((match = re.exec(str)) != null) {
console.log("match found at " + match.index);
if (guard-- < 0) {
console.error("Infinite loop detected")
break;
}
}
var re = /\b./g,
str = "hello world";
var guard = 10;
while ((match = re.exec(str)) != null) {
console.log("match found at " + match.index);
if (guard-- < 0) {
console.error("Infinite loop detected")
break;
}
}
更好的解决方案(只适用于较新的浏览器/在旧版/IE版本上需要填充)是使用String.prototype.matchAll()。
var re = /\b/g,
str = "hello world";
console.log(Array.from(str.matchAll(re)).map(match => match.index))
解释:
String.prototype.matchAll()
期望一个全局正则表达式(即带有全局标志g
的正则表达式)。它返回一个迭代器。为了循环遍历并map()
这个迭代器,它必须被转换为数组(这正是Array.from()
所做的)。与RegExp.prototype.exec()
的结果类似,根据规范,生成的元素具有一个.index
字段。
请参见String.prototype.matchAll()和Array.from() MDN页面以获取浏览器支持和polyfill选项。
RegExp.prototype.exec()
的问题在于它会更新正则表达式的 lastIndex
指针,并且下一次搜索将从先前找到的 lastIndex
开始。
var re = /l/g,
str = "hello world";
console.log(re.lastIndex)
re.exec(str)
console.log(re.lastIndex)
re.exec(str)
console.log(re.lastIndex)
re.exec(str)
console.log(re.lastIndex)
/(?=l)/g
是一个前瞻匹配 l 的正则表达式 -- 它匹配 l
前面的0宽度字符串。所以第一次调用exec()
时正确地到达了索引2,然后就停在那里了)。
var re = /(?=l)/g,
str = "hello world";
console.log(re.lastIndex)
re.exec(str)
console.log(re.lastIndex)
re.exec(str)
console.log(re.lastIndex)
re.exec(str)
console.log(re.lastIndex)
The solution (that is less nice than matchAll(), but should work on all browsers) therefore is to manually increase the lastIndex if the match width is 0 (which may be checked in different ways)
var re = /\b/g,
str = "hello world";
while ((match = re.exec(str)) != null) {
console.log("match found at " + match.index);
// alternative: if (match.index == re.lastIndex) {
if (match[0].length == 0) {
// we need to increase lastIndex -- this location was already matched,
// we don't want to match it again (and get into an infinite loop)
re.lastIndex++
}
}
var str = "The rain in SPAIN stays mainly in the plain";
function searchIndex(str, searchValue, isCaseSensitive) {
var modifiers = isCaseSensitive ? 'gi' : 'g';
var regExpValue = new RegExp(searchValue, modifiers);
var matches = [];
var startIndex = 0;
var arr = str.match(regExpValue);
[].forEach.call(arr, function(element) {
startIndex = str.indexOf(element, startIndex);
matches.push(startIndex++);
});
return matches;
}
console.log(searchIndex(str, 'ain', true));
str.indexOf
只会找到匹配文本的下一个出现位置,而不一定是匹配项本身。JS正则表达式支持在捕获之外的文本上使用前瞻条件。例如 searchIndex("foobarfoobaz", "foo(?=baz)", true)
应该返回 [6]
,而不是 [0]
。 - rakslice[].forEach.call(arr, function(element)
而不是 arr.forEach 或 arr.map? - Ankit KumarString.prototype.matching_positions = function( _word, _case_sensitive, _whole_words, _multiline )
{
/*besides '_word' param, others are flags (0|1)*/
var _match_pattern = "g"+(_case_sensitive?"i":"")+(_multiline?"m":"") ;
var _bound = _whole_words ? "\\b" : "" ;
var _re = new RegExp( _bound+_word+_bound, _match_pattern );
var _pos = [], _chunk, _index = 0 ;
while( true )
{
_chunk = _re.exec( this ) ;
if ( _chunk == null ) break ;
_pos.push( _chunk['index'] ) ;
_re.lastIndex = _chunk['index']+1 ;
}
return _pos ;
}
var _sentence = "What do doers want ? What do doers need ?" ;
var _word = "do" ;
console.log( _sentence.matching_positions( _word, 1, 0, 0 ) );
console.log( _sentence.matching_positions( _word, 1, 1, 0 ) );
你也可以输入正则表达式:
var _second = "z^2+2z-1" ;
console.log( _second.matching_positions( "[0-9]\z+", 0, 0, 0 ) );
这里得到线性项的位置索引。
我有幸使用了基于matchAll
的单行解决方案(我的用例需要一个字符串位置数组)
let regexp = /bar/g;
let str = 'foobarfoobar';
let matchIndices = Array.from(str.matchAll(regexp)).map(x => x.index);
console.log(matchIndices)
输出结果: [3, 9]
re
作为变量,并添加g
修饰符都是至关重要的!否则你将会陷入无尽的循环中。 - oriadamundefined
。https://jsfiddle.net/6uwn1vof/2/,这不像你的那个例子是一个类似搜索的例子。 - Onur Yıldırımg
标志,它就可以工作了。由于match
是字符串的函数,而不是正则表达式,所以它不能像exec
一样具有状态,因此只有在您不寻找全局匹配时(即状态无关紧要)才会将其视为exec
(即具有索引属性)。 - Jimbo Jonny