提问人:stagas 提问时间:2/19/2010 更新时间:8/11/2022 访问量:186933
在 Javascript 中返回正则表达式 match() 的位置?
Return positions of a regex match() in Javascript?
答:
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);
}
评论
re
g
undefined
g
match
exec
exec
您可以使用对象的方法。这仅适用于第一个匹配项,但会执行您描述的操作。例如:search
String
"How are you?".search(/are/);
// 4
这是我想出的:
// 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
也适用于终端位置。
match.index + match[0].length - 1
.slice()
.substring()
-1
patt = /.*/
此成员 fn 返回 String 对象中输入字的从 0 开始的位置(如果有)的数组
String.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 ) );
这里得到线性项的位置指数。
从 developer.mozilla.org String 方法的文档中:.match()
返回的 Array 有一个额外的输入属性,其中包含 已分析的原始字符串。此外,它还有一个索引 属性,表示 字符串。
当处理非全局正则表达式(即,正则表达式上没有标志)时,返回的值有一个属性...您所要做的就是访问它。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。
评论
index
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
searchIndex("foobarfoobaz", "foo(?=baz)", true)
[6]
[0]
这是我最近发现的一个很酷的功能,我在控制台上尝试了这个,它似乎有效:
var text = "border-bottom-left-radius";
var newText = text.replace(/-/g,function(match, index){
return " " + index + " ";
});
返回:“边界 6 底部 13 左 18 半径”
所以这似乎是你要找的。
评论
arguments
function trimRegex(str, regex){
return str.substr(str.match(regex).index).split('').reverse().join('').substr(str.match(regex).index).split('').reverse().join('');
}
let test = '||ab||cd||';
trimRegex(test, /[^|]/);
console.log(test); //output: ab||cd
或
function trimChar(str, trim, req){
let regex = new RegExp('[^'+trim+']');
return str.substr(str.match(regex).index).split('').reverse().join('').substr(str.match(regex).index).split('').reverse().join('');
}
let test = '||ab||cd||';
trimChar(test, '|');
console.log(test); //output: ab||cd
在现代浏览器中,你可以使用 string.matchAll() 来实现这一点。
这种方法的好处是,它不依赖于正则表达式是有状态的,就像@Gumbo的回答一样。RegExp.exec()
let regexp = /bar/g;
let str = 'foobarfoobar';
let matches = [...str.matchAll(regexp)];
matches.forEach((match) => {
console.log("match found at " + match.index);
});
评论
matchAll
g
var str = 'my string here';
var index = str.match(/hre/).index;
alert(index); // <- 10
评论
恐怕前面的答案(基于)似乎不起作用,以防您的正则表达式与宽度 0 匹配。例如(注意:是应该找到所有单词边界的正则表达式):exec
/\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;
}
}
可以尝试通过让正则表达式匹配至少 1 个字符来解决这个问题,但这远非理想(这意味着您必须在字符串末尾手动添加索引)
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 版本上使用 polyfill)是使用 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)
只要正则表达式匹配实际上具有宽度,这就可以很好地工作。如果使用 0 宽度的正则表达式,则此指针不会增加,因此您将获得无限循环(注意:是 l 的展望 - 它与 .因此,它在第一次调用 时正确地转到索引 2,然后停留在那里:/(?=l)/g
l
exec()
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)
因此,解决方案(不如matchAll()好,但应该适用于所有浏览器)是如果匹配宽度为0(可以用不同的方式检查),则手动增加lastIndex
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++
}
}
我很幸运地使用了这个基于(我的用例需要字符串位置数组)的单行解决方案matchAll
let regexp = /bar/g;
let str = 'foobarfoobar';
let matchIndices = Array.from(str.matchAll(regexp)).map(x => x.index);
console.log(matchIndices)
输出: [3, 9]
评论