[英]Return positions of a regex match() in Javascript?
有沒有辦法在 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); }
在現代瀏覽器中,您可以使用string.matchAll()完成此操作。
這種方法與RegExp.exec()
的好處是它不依賴於有狀態的正則表達式,就像@Gumbo's answer中那樣。
let regexp = /bar/g; let str = 'foobarfoobar'; let matches = [...str.matchAll(regexp)]; matches.forEach((match) => { console.log("match found at " + match.index); });
來自developer.mozilla.org關於 String .match()
方法的文檔:
返回的 Array 有一個額外的輸入屬性,其中包含已解析的原始字符串。 此外,它還有一個 index 屬性,表示字符串中匹配項的從零開始的索引。
在處理非全局正則表達式(即,正則表達式上沒有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。
您可以使用String
對象的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 半徑”
所以這似乎是你正在尋找的。
如果您的正則表達式與寬度 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
字段。
有關瀏覽器支持和 polyfill 選項,請參閱String.prototype.matchAll()和Array.from() MDN 頁面。
編輯:深入挖掘以尋找所有瀏覽器都支持的解決方案
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)/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)
解決方案(不如 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++ } }
此成員 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 ) );
這里得到線性項的位置索引。
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));
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.prototype.searchAll = function(regex) {
return [...this.matchAll(regex)].map((match) => {return match.index});
}
// then use it
"1test2".searchAll(/\d/g) // [ 0, 5 ]
請注意,您必須使用 /g Global 標志才能使其工作
我很幸運地使用了這個基於matchAll
的單行解決方案(我的用例需要一個字符串位置數組)
let regexp = /bar/g;
let str = 'foobarfoobar';
let matchIndices = Array.from(str.matchAll(regexp)).map(x => x.index);
console.log(matchIndices)
輸出:[3, 9]
var str = 'my string here'; var index = str.match(/hre/).index; alert(index); // <- 10
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.