정규 표현식을 허용하는 JavaScript의 String.indexOf () 버전이 있습니까?
자바 스크립트에서 첫 번째 첫 번째 매개 변수의 문자열 대신 정규 표현식을 사용하면서 두 번째 매개 변수를 허용하는 String.indexOf ()와 동등한 것이 있습니까?
나는 뭔가를해야합니다
str.indexOf(/[abc]/ , i);
과
str.lastIndexOf(/[abc]/ , i);
String.search ()는 정규 표현식을 매개 변수로 사용하지만 두 번째 인수를 지정할 수는 없습니다!
편집 :
이것은 원래 생각했던 것보다 더 어려워서 제공된 모든 솔루션을 테스트하기 위해 작은 테스트 함수를 작성했습니다 ... regexIndexOf 및 regexLastIndexOf가 String 객체에 추가되었다고 가정합니다.
function test (str) {
var i = str.length +2;
while (i--) {
if (str.indexOf('a',i) != str.regexIndexOf(/a/,i))
alert (['failed regexIndexOf ' , str,i , str.indexOf('a',i) , str.regexIndexOf(/a/,i)]) ;
if (str.lastIndexOf('a',i) != str.regexLastIndexOf(/a/,i) )
alert (['failed regexLastIndexOf ' , str,i,str.lastIndexOf('a',i) , str.regexLastIndexOf(/a/,i)]) ;
}
}
적어도 하나의 문자 정규 표현식에 대해 indexOf를 사용하는 것과 결과가 동일한 지 확인하기 위해 다음과 같이 테스트하고 있습니다.
// xes
test ( 'xxx'); 중 a를 찾으십시오 .
테스트 ( 'axx');
테스트 ( 'xax');
테스트 ( 'xxa');
테스트 ( 'axa');
테스트 ( 'xaa');
테스트 ( 'aax');
테스트 ( 'aaa');
이미 언급 한 몇 가지 접근법 (indexOf는 분명히 간단합니다)을 결합하여 트릭을 수행하는 함수라고 생각합니다.
String.prototype.regexIndexOf = function(regex, startpos) {
var indexOf = this.substring(startpos || 0).search(regex);
return (indexOf >= 0) ? (indexOf + (startpos || 0)) : indexOf;
}
String.prototype.regexLastIndexOf = function(regex, startpos) {
regex = (regex.global) ? regex : new RegExp(regex.source, "g" + (regex.ignoreCase ? "i" : "") + (regex.multiLine ? "m" : ""));
if(typeof (startpos) == "undefined") {
startpos = this.length;
} else if(startpos < 0) {
startpos = 0;
}
var stringToWorkWith = this.substring(0, startpos + 1);
var lastIndexOf = -1;
var nextStop = 0;
while((result = regex.exec(stringToWorkWith)) != null) {
lastIndexOf = result.index;
regex.lastIndex = ++nextStop;
}
return lastIndexOf;
}
분명히, 내장 String 객체를 수정하면 대부분의 사람들에게 붉은 깃발을 보낼 수 있지만, 그렇게 큰 문제는 아닐 수 있습니다. 간단히 알아 두십시오.
업데이트 : 지금 regexLastIndexOf()
모방 된 것처럼 편집 lastIndexOf()
되었습니다. 그래도 실패하면 어떤 상황에서 알려주십시오.
업데이트 :이 페이지의 주석에서 찾은 모든 테스트와 내 테스트를 통과합니다. 물론 이것이 방탄을 의미하지는 않습니다. 모든 의견을 부탁드립니다.
String
생성자의 인스턴스 에는 RegExp를 허용하고 첫 번째 일치하는 인덱스를 반환 하는 .search()
메서드 가 있습니다.
특정 위치에서 검색을 시작하려면 (의 두 번째 매개 변수에 해당 .indexOf()
) slice
첫 번째 i
문자를 해제 할 수 있습니다 .
str.slice(i).search(/re/)
그러나 이것은 짧은 문자열 (첫 번째 부분이 슬라이스 된 후)에 i
색인 을 가져 오므로 잘린 부분 ( ) 의 길이를 반환되지 않은 인덱스에 반환하려고합니다 -1
. 이것은 원래 문자열의 색인을 제공합니다.
function regexIndexOf(text, re, i) {
var indexInSuffix = text.slice(i).search(re);
return indexInSuffix < 0 ? indexInSuffix : indexInSuffix + i;
}
짧은 버전이 있습니다. 그것은 나를 위해 잘 작동합니다!
var match = str.match(/[abc]/gi);
var firstIndex = str.indexOf(match[0]);
var lastIndex = str.lastIndexOf(match[match.length-1]);
그리고 프로토 타입 버전을 원한다면 :
String.prototype.indexOfRegex = function(regex){
var match = this.match(regex);
return match ? this.indexOf(match[0]) : -1;
}
String.prototype.lastIndexOfRegex = function(regex){
var match = this.match(regex);
return match ? this.lastIndexOf(match[match.length-1]) : -1;
}
편집 : fromIndex에 대한 지원을 추가하려는 경우
String.prototype.indexOfRegex = function(regex, fromIndex){
var str = fromIndex ? this.substring(fromIndex) : this;
var match = str.match(regex);
return match ? str.indexOf(match[0]) + fromIndex : -1;
}
String.prototype.lastIndexOfRegex = function(regex, fromIndex){
var str = fromIndex ? this.substring(0, fromIndex) : this;
var match = str.match(regex);
return match ? str.lastIndexOf(match[match.length-1]) : -1;
}
다음과 같이 간단하게 사용하십시오.
var firstIndex = str.indexOfRegex(/[abc]/gi);
var lastIndex = str.lastIndexOfRegex(/[abc]/gi);
사용하다:
str.search(regex)
BaileyP의 답변을 기반으로합니다. 가장 큰 차이점은 -1
패턴을 일치시킬 수없는 경우 이러한 메소드가 리턴한다는 것입니다.
편집 : Jason Bunting의 답변 덕분에 아이디어가 생겼습니다. 왜 .lastIndex
정규식 의 속성을 수정하지 않습니까? 비록 이것이 글로벌 플래그 ( /g
) 가있는 패턴에서만 작동합니다 .
편집 : 테스트 사례를 통과하도록 업데이트되었습니다.
String.prototype.regexIndexOf = function(re, startPos) {
startPos = startPos || 0;
if (!re.global) {
var flags = "g" + (re.multiline?"m":"") + (re.ignoreCase?"i":"");
re = new RegExp(re.source, flags);
}
re.lastIndex = startPos;
var match = re.exec(this);
if (match) return match.index;
else return -1;
}
String.prototype.regexLastIndexOf = function(re, startPos) {
startPos = startPos === undefined ? this.length : startPos;
if (!re.global) {
var flags = "g" + (re.multiline?"m":"") + (re.ignoreCase?"i":"");
re = new RegExp(re.source, flags);
}
var lastSuccess = -1;
for (var pos = 0; pos <= startPos; pos++) {
re.lastIndex = pos;
var match = re.exec(this);
if (!match) break;
pos = match.index;
if (pos <= startPos) lastSuccess = pos;
}
return lastSuccess;
}
substr을 사용할 수 있습니다.
str.substr(i).match(/[abc]/);
RexExp
인스턴스에는 이미 lastIndex 속성이 있습니다 (글로벌 인 경우). 내가하는 일은 정규 표현식을 복사하여 목적에 맞게 약간 수정 exec
하고 문자열 에서 확인 하고을 보는 것 lastIndex
입니다. 이것은 문자열을 반복하는 것보다 필연적으로 빠릅니다. (이것을 문자열 프로토 타입에 넣는 방법에 대한 충분한 예가 있습니까?)
function reIndexOf(reIn, str, startIndex) {
var re = new RegExp(reIn.source, 'g' + (reIn.ignoreCase ? 'i' : '') + (reIn.multiLine ? 'm' : ''));
re.lastIndex = startIndex || 0;
var res = re.exec(str);
if(!res) return -1;
return re.lastIndex - res[0].length;
};
function reLastIndexOf(reIn, str, startIndex) {
var src = /\$$/.test(reIn.source) && !/\\\$$/.test(reIn.source) ? reIn.source : reIn.source + '(?![\\S\\s]*' + reIn.source + ')';
var re = new RegExp(src, 'g' + (reIn.ignoreCase ? 'i' : '') + (reIn.multiLine ? 'm' : ''));
re.lastIndex = startIndex || 0;
var res = re.exec(str);
if(!res) return -1;
return re.lastIndex - res[0].length;
};
reIndexOf(/[abc]/, "tommy can eat"); // Returns 6
reIndexOf(/[abc]/, "tommy can eat", 8); // Returns 11
reLastIndexOf(/[abc]/, "tommy can eat"); // Returns 11
RegExp 객체에 함수를 프로토 타입 할 수도 있습니다.
RegExp.prototype.indexOf = function(str, startIndex) {
var re = new RegExp(this.source, 'g' + (this.ignoreCase ? 'i' : '') + (this.multiLine ? 'm' : ''));
re.lastIndex = startIndex || 0;
var res = re.exec(str);
if(!res) return -1;
return re.lastIndex - res[0].length;
};
RegExp.prototype.lastIndexOf = function(str, startIndex) {
var src = /\$$/.test(this.source) && !/\\\$$/.test(this.source) ? this.source : this.source + '(?![\\S\\s]*' + this.source + ')';
var re = new RegExp(src, 'g' + (this.ignoreCase ? 'i' : '') + (this.multiLine ? 'm' : ''));
re.lastIndex = startIndex || 0;
var res = re.exec(str);
if(!res) return -1;
return re.lastIndex - res[0].length;
};
/[abc]/.indexOf("tommy can eat"); // Returns 6
/[abc]/.indexOf("tommy can eat", 8); // Returns 11
/[abc]/.lastIndexOf("tommy can eat"); // Returns 11
수정 방법에 대한 간단한 설명 RegExp
: indexOf
전역 플래그가 설정되어 있는지 확인해야합니다. 들어 lastIndexOf
나는하지 않는 한 마지막 발생을 찾을 부정적인 모양 미리를 사용하고의 RegExp
이미 문자열의 끝에 일치했다.
기본적으로는 아니지만이 기능을 추가 할 수 있습니다.
<script type="text/javascript">
String.prototype.regexIndexOf = function( pattern, startIndex )
{
startIndex = startIndex || 0;
var searchResult = this.substr( startIndex ).search( pattern );
return ( -1 === searchResult ) ? -1 : searchResult + startIndex;
}
String.prototype.regexLastIndexOf = function( pattern, startIndex )
{
startIndex = startIndex === undefined ? this.length : startIndex;
var searchResult = this.substr( 0, startIndex ).reverse().regexIndexOf( pattern, 0 );
return ( -1 === searchResult ) ? -1 : this.length - ++searchResult;
}
String.prototype.reverse = function()
{
return this.split('').reverse().join('');
}
// Indexes 0123456789
var str = 'caabbccdda';
alert( [
str.regexIndexOf( /[cd]/, 4 )
, str.regexLastIndexOf( /[cd]/, 4 )
, str.regexIndexOf( /[yz]/, 4 )
, str.regexLastIndexOf( /[yz]/, 4 )
, str.lastIndexOf( 'd', 4 )
, str.regexLastIndexOf( /d/, 4 )
, str.lastIndexOf( 'd' )
, str.regexLastIndexOf( /d/ )
]
);
</script>
나는이 방법을 완전히 테스트하지는 않았지만 지금까지는 효과가있는 것 같습니다.
제안 된 솔루션이 모두 테스트에 실패하거나 실패한 후 (편집 : 일부는이를 작성한 후 테스트를 통과하도록 업데이트되었습니다) Array.indexOf 및 Array.lastIndexOf에 대한 mozilla 구현을 찾았 습니다.
다음과 같이 String.prototype.regexIndexOf 및 String.prototype.regexLastIndexOf 버전을 구현하는 데 사용했습니다.
String.prototype.regexIndexOf = function(elt /*, from*/)
{
var arr = this.split('');
var len = arr.length;
var from = Number(arguments[1]) || 0;
from = (from < 0) ? Math.ceil(from) : Math.floor(from);
if (from < 0)
from += len;
for (; from < len; from++) {
if (from in arr && elt.exec(arr[from]) )
return from;
}
return -1;
};
String.prototype.regexLastIndexOf = function(elt /*, from*/)
{
var arr = this.split('');
var len = arr.length;
var from = Number(arguments[1]);
if (isNaN(from)) {
from = len - 1;
} else {
from = (from < 0) ? Math.ceil(from) : Math.floor(from);
if (from < 0)
from += len;
else if (from >= len)
from = len - 1;
}
for (; from > -1; from--) {
if (from in arr && elt.exec(arr[from]) )
return from;
}
return -1;
};
그들은 내가 질문에서 제공 한 테스트 기능을 통과 한 것 같습니다.
정규식이 한 문자와 일치하는 경우에만 작동하지만 ([abc], \ s, \ W, \ D)
누군가 정규 표현식에서 작동하는 더 나은 / 더 빠른 / 더 깨끗한 / 더 일반적인 구현을 제공하는 경우 질문을 계속 모니터링 할 것입니다.
regexIndexOf
배열에도 함수가 필요 했기 때문에 직접 프로그래밍했습니다. 그러나 나는 그것이 최적화되어 있는지 의심하지만 그것이 제대로 작동해야한다고 생각합니다.
Array.prototype.regexIndexOf = function (regex, startpos = 0) {
len = this.length;
for(x = startpos; x < len; x++){
if(typeof this[x] != 'undefined' && (''+this[x]).match(regex)){
return x;
}
}
return -1;
}
arr = [];
arr.push(null);
arr.push(NaN);
arr[3] = 7;
arr.push('asdf');
arr.push('qwer');
arr.push(9);
arr.push('...');
console.log(arr);
arr.regexIndexOf(/\d/, 4);
간단한 경우에는 split을 사용하여 역방향 검색을 단순화 할 수 있습니다.
function regexlast(string,re){
var tokens=string.split(re);
return (tokens.length>1)?(string.length-tokens[tokens.length-1].length):null;
}
몇 가지 심각한 문제가 있습니다.
- 겹치는 경기가 표시되지 않습니다
- 반환 된 인덱스는 시작이 아닌 일치 종료에 대한 것입니다 (정규 표현식이 상수 인 경우 적합)
그러나 밝은면에서는 코드가 적습니다. /\s\w/
단어 경계를 찾는 것과 같이 겹칠 수없는 일정한 길이의 정규 표현식의 경우 충분합니다.
일치하지 않는 데이터가있는 경우 string.search를 사용하는 것이 브라우저에서 가장 빠릅니다. 각 반복마다 문자열을 다시 슬라이스합니다.
function lastIndexOfSearch(string, regex, index) {
if(index === 0 || index)
string = string.slice(0, Math.max(0,index));
var idx;
var offset = -1;
while ((idx = string.search(regex)) !== -1) {
offset += idx + 1;
string = string.slice(idx + 1);
}
return offset;
}
조밀 한 데이터를 위해 이것을 만들었습니다. 실행 방법과 비교하면 복잡하지만 밀도가 높은 데이터의 경우 다른 모든 방법보다 2-10 배 빠르며 허용되는 솔루션보다 약 100 배 빠릅니다. 요점은 다음과 같습니다.
- 한 번 전달 된 정규식에서 exec를 호출하여 일치하는 항목이 있는지 확인하거나 조기에 종료합니다. 비슷한 방법으로 (? =를 사용 하여이 작업을 수행하지만 exec로 IE를 검사하는 것이 훨씬 빠릅니다.
- 수정 된 정규식을 '(r) 형식으로 구성하고 캐시합니다. (?!. ? r) '
새로운 정규식이 실행되고 해당 exec 또는 첫 번째 exec의 결과가 리턴됩니다.
function lastIndexOfGroupSimple(string, regex, index) { if (index === 0 || index) string = string.slice(0, Math.max(0, index + 1)); regex.lastIndex = 0; var lastRegex, index flags = 'g' + (regex.multiline ? 'm' : '') + (regex.ignoreCase ? 'i' : ''), key = regex.source + '$' + flags, match = regex.exec(string); if (!match) return -1; if (lastIndexOfGroupSimple.cache === undefined) lastIndexOfGroupSimple.cache = {}; lastRegex = lastIndexOfGroupSimple.cache[key]; if (!lastRegex) lastIndexOfGroupSimple.cache[key] = lastRegex = new RegExp('.*(' + regex.source + ')(?!.*?' + regex.source + ')', flags); index = match.index; lastRegex.lastIndex = match.index; return (match = lastRegex.exec(string)) ? lastRegex.lastIndex - match[1].length : index; };
나는 시험의 목적을 이해하지 못한다. 정규식이 필요한 상황은 indexOf에 대한 호출과 비교할 수 없으며, 처음에는 메소드를 만드는 지점이라고 생각합니다. 테스트를 통과하려면 정규식 반복 방식을 조정하는 것보다 'xxx + (?! x)'를 사용하는 것이 좋습니다.
Jason Bunting의 마지막 색인이 작동하지 않습니다. 광산은 최적은 아니지만 작동합니다.
//Jason Bunting's
String.prototype.regexIndexOf = function(regex, startpos) {
var indexOf = this.substring(startpos || 0).search(regex);
return (indexOf >= 0) ? (indexOf + (startpos || 0)) : indexOf;
}
String.prototype.regexLastIndexOf = function(regex, startpos) {
var lastIndex = -1;
var index = this.regexIndexOf( regex );
startpos = startpos === undefined ? this.length : startpos;
while ( index >= 0 && index < startpos )
{
lastIndex = index;
index = this.regexIndexOf( regex, index + 1 );
}
return lastIndex;
}
요청 된 작업을 수행하는 기본 메소드는 여전히 없습니다.
사용중인 코드는 다음과 같습니다. String.prototype.indexOf 및 String.prototype.lastIndexOf 메서드 의 동작을 모방 하지만 검색 할 값을 나타내는 문자열 외에도 RegExp를 검색 인수로 허용합니다.
그렇습니다. 가능한 한 현재 표준을 최대한 가깝게 따르려고 노력하고 있으며, 상당한 양의 JSDOC 의견이 포함되어 있습니다 . 그러나 일단 축소되면 코드는 2.27k에 불과하며 전송을 위해 gzipped되면 1023 바이트에 불과합니다.
이것이 추가되는 두 가지 방법 String.prototype
(사용 가능한 경우 Object.defineProperty 사용)은 다음과 같습니다.
searchOf
searchLastOf
OP가 게시 한 모든 테스트를 통과했으며 추가적으로 일상적으로 사용하는 루틴을 철저히 테스트했으며 여러 환경에서 작동하는지 확인하려고했지만 피드백 / 문제는 항상 환영합니다.
/*jslint maxlen:80, browser:true */
/*
* Properties used by searchOf and searchLastOf implementation.
*/
/*property
MAX_SAFE_INTEGER, abs, add, apply, call, configurable, defineProperty,
enumerable, exec, floor, global, hasOwnProperty, ignoreCase, index,
lastIndex, lastIndexOf, length, max, min, multiline, pow, prototype,
remove, replace, searchLastOf, searchOf, source, toString, value, writable
*/
/*
* Properties used in the testing of searchOf and searchLastOf implimentation.
*/
/*property
appendChild, createTextNode, getElementById, indexOf, lastIndexOf, length,
searchLastOf, searchOf, unshift
*/
(function () {
'use strict';
var MAX_SAFE_INTEGER = Number.MAX_SAFE_INTEGER || Math.pow(2, 53) - 1,
getNativeFlags = new RegExp('\\/([a-z]*)$', 'i'),
clipDups = new RegExp('([\\s\\S])(?=[\\s\\S]*\\1)', 'g'),
pToString = Object.prototype.toString,
pHasOwn = Object.prototype.hasOwnProperty,
stringTagRegExp;
/**
* Defines a new property directly on an object, or modifies an existing
* property on an object, and returns the object.
*
* @private
* @function
* @param {Object} object
* @param {string} property
* @param {Object} descriptor
* @returns {Object}
* @see https://goo.gl/CZnEqg
*/
function $defineProperty(object, property, descriptor) {
if (Object.defineProperty) {
Object.defineProperty(object, property, descriptor);
} else {
object[property] = descriptor.value;
}
return object;
}
/**
* Returns true if the operands are strictly equal with no type conversion.
*
* @private
* @function
* @param {*} a
* @param {*} b
* @returns {boolean}
* @see http://www.ecma-international.org/ecma-262/5.1/#sec-11.9.4
*/
function $strictEqual(a, b) {
return a === b;
}
/**
* Returns true if the operand inputArg is undefined.
*
* @private
* @function
* @param {*} inputArg
* @returns {boolean}
*/
function $isUndefined(inputArg) {
return $strictEqual(typeof inputArg, 'undefined');
}
/**
* Provides a string representation of the supplied object in the form
* "[object type]", where type is the object type.
*
* @private
* @function
* @param {*} inputArg The object for which a class string represntation
* is required.
* @returns {string} A string value of the form "[object type]".
* @see http://www.ecma-international.org/ecma-262/5.1/#sec-15.2.4.2
*/
function $toStringTag(inputArg) {
var val;
if (inputArg === null) {
val = '[object Null]';
} else if ($isUndefined(inputArg)) {
val = '[object Undefined]';
} else {
val = pToString.call(inputArg);
}
return val;
}
/**
* The string tag representation of a RegExp object.
*
* @private
* @type {string}
*/
stringTagRegExp = $toStringTag(getNativeFlags);
/**
* Returns true if the operand inputArg is a RegExp.
*
* @private
* @function
* @param {*} inputArg
* @returns {boolean}
*/
function $isRegExp(inputArg) {
return $toStringTag(inputArg) === stringTagRegExp &&
pHasOwn.call(inputArg, 'ignoreCase') &&
typeof inputArg.ignoreCase === 'boolean' &&
pHasOwn.call(inputArg, 'global') &&
typeof inputArg.global === 'boolean' &&
pHasOwn.call(inputArg, 'multiline') &&
typeof inputArg.multiline === 'boolean' &&
pHasOwn.call(inputArg, 'source') &&
typeof inputArg.source === 'string';
}
/**
* The abstract operation throws an error if its argument is a value that
* cannot be converted to an Object, otherwise returns the argument.
*
* @private
* @function
* @param {*} inputArg The object to be tested.
* @throws {TypeError} If inputArg is null or undefined.
* @returns {*} The inputArg if coercible.
* @see https://goo.gl/5GcmVq
*/
function $requireObjectCoercible(inputArg) {
var errStr;
if (inputArg === null || $isUndefined(inputArg)) {
errStr = 'Cannot convert argument to object: ' + inputArg;
throw new TypeError(errStr);
}
return inputArg;
}
/**
* The abstract operation converts its argument to a value of type string
*
* @private
* @function
* @param {*} inputArg
* @returns {string}
* @see https://people.mozilla.org/~jorendorff/es6-draft.html#sec-tostring
*/
function $toString(inputArg) {
var type,
val;
if (inputArg === null) {
val = 'null';
} else {
type = typeof inputArg;
if (type === 'string') {
val = inputArg;
} else if (type === 'undefined') {
val = type;
} else {
if (type === 'symbol') {
throw new TypeError('Cannot convert symbol to string');
}
val = String(inputArg);
}
}
return val;
}
/**
* Returns a string only if the arguments is coercible otherwise throws an
* error.
*
* @private
* @function
* @param {*} inputArg
* @throws {TypeError} If inputArg is null or undefined.
* @returns {string}
*/
function $onlyCoercibleToString(inputArg) {
return $toString($requireObjectCoercible(inputArg));
}
/**
* The function evaluates the passed value and converts it to an integer.
*
* @private
* @function
* @param {*} inputArg The object to be converted to an integer.
* @returns {number} If the target value is NaN, null or undefined, 0 is
* returned. If the target value is false, 0 is returned
* and if true, 1 is returned.
* @see http://www.ecma-international.org/ecma-262/5.1/#sec-9.4
*/
function $toInteger(inputArg) {
var number = +inputArg,
val = 0;
if ($strictEqual(number, number)) {
if (!number || number === Infinity || number === -Infinity) {
val = number;
} else {
val = (number > 0 || -1) * Math.floor(Math.abs(number));
}
}
return val;
}
/**
* Copies a regex object. Allows adding and removing native flags while
* copying the regex.
*
* @private
* @function
* @param {RegExp} regex Regex to copy.
* @param {Object} [options] Allows specifying native flags to add or
* remove while copying the regex.
* @returns {RegExp} Copy of the provided regex, possibly with modified
* flags.
*/
function $copyRegExp(regex, options) {
var flags,
opts,
rx;
if (options !== null && typeof options === 'object') {
opts = options;
} else {
opts = {};
}
// Get native flags in use
flags = getNativeFlags.exec($toString(regex))[1];
flags = $onlyCoercibleToString(flags);
if (opts.add) {
flags += opts.add;
flags = flags.replace(clipDups, '');
}
if (opts.remove) {
// Would need to escape `options.remove` if this was public
rx = new RegExp('[' + opts.remove + ']+', 'g');
flags = flags.replace(rx, '');
}
return new RegExp(regex.source, flags);
}
/**
* The abstract operation ToLength converts its argument to an integer
* suitable for use as the length of an array-like object.
*
* @private
* @function
* @param {*} inputArg The object to be converted to a length.
* @returns {number} If len <= +0 then +0 else if len is +INFINITY then
* 2^53-1 else min(len, 2^53-1).
* @see https://people.mozilla.org/~jorendorff/es6-draft.html#sec-tolength
*/
function $toLength(inputArg) {
return Math.min(Math.max($toInteger(inputArg), 0), MAX_SAFE_INTEGER);
}
/**
* Copies a regex object so that it is suitable for use with searchOf and
* searchLastOf methods.
*
* @private
* @function
* @param {RegExp} regex Regex to copy.
* @returns {RegExp}
*/
function $toSearchRegExp(regex) {
return $copyRegExp(regex, {
add: 'g',
remove: 'y'
});
}
/**
* Returns true if the operand inputArg is a member of one of the types
* Undefined, Null, Boolean, Number, Symbol, or String.
*
* @private
* @function
* @param {*} inputArg
* @returns {boolean}
* @see https://goo.gl/W68ywJ
* @see https://goo.gl/ev7881
*/
function $isPrimitive(inputArg) {
var type = typeof inputArg;
return type === 'undefined' ||
inputArg === null ||
type === 'boolean' ||
type === 'string' ||
type === 'number' ||
type === 'symbol';
}
/**
* The abstract operation converts its argument to a value of type Object
* but fixes some environment bugs.
*
* @private
* @function
* @param {*} inputArg The argument to be converted to an object.
* @throws {TypeError} If inputArg is not coercible to an object.
* @returns {Object} Value of inputArg as type Object.
* @see http://www.ecma-international.org/ecma-262/5.1/#sec-9.9
*/
function $toObject(inputArg) {
var object;
if ($isPrimitive($requireObjectCoercible(inputArg))) {
object = Object(inputArg);
} else {
object = inputArg;
}
return object;
}
/**
* Converts a single argument that is an array-like object or list (eg.
* arguments, NodeList, DOMTokenList (used by classList), NamedNodeMap
* (used by attributes property)) into a new Array() and returns it.
* This is a partial implementation of the ES6 Array.from
*
* @private
* @function
* @param {Object} arrayLike
* @returns {Array}
*/
function $toArray(arrayLike) {
var object = $toObject(arrayLike),
length = $toLength(object.length),
array = [],
index = 0;
array.length = length;
while (index < length) {
array[index] = object[index];
index += 1;
}
return array;
}
if (!String.prototype.searchOf) {
/**
* This method returns the index within the calling String object of
* the first occurrence of the specified value, starting the search at
* fromIndex. Returns -1 if the value is not found.
*
* @function
* @this {string}
* @param {RegExp|string} regex A regular expression object or a String.
* Anything else is implicitly converted to
* a String.
* @param {Number} [fromIndex] The location within the calling string
* to start the search from. It can be any
* integer. The default value is 0. If
* fromIndex < 0 the entire string is
* searched (same as passing 0). If
* fromIndex >= str.length, the method will
* return -1 unless searchValue is an empty
* string in which case str.length is
* returned.
* @returns {Number} If successful, returns the index of the first
* match of the regular expression inside the
* string. Otherwise, it returns -1.
*/
$defineProperty(String.prototype, 'searchOf', {
enumerable: false,
configurable: true,
writable: true,
value: function (regex) {
var str = $onlyCoercibleToString(this),
args = $toArray(arguments),
result = -1,
fromIndex,
match,
rx;
if (!$isRegExp(regex)) {
return String.prototype.indexOf.apply(str, args);
}
if ($toLength(args.length) > 1) {
fromIndex = +args[1];
if (fromIndex < 0) {
fromIndex = 0;
}
} else {
fromIndex = 0;
}
if (fromIndex >= $toLength(str.length)) {
return result;
}
rx = $toSearchRegExp(regex);
rx.lastIndex = fromIndex;
match = rx.exec(str);
if (match) {
result = +match.index;
}
return result;
}
});
}
if (!String.prototype.searchLastOf) {
/**
* This method returns the index within the calling String object of
* the last occurrence of the specified value, or -1 if not found.
* The calling string is searched backward, starting at fromIndex.
*
* @function
* @this {string}
* @param {RegExp|string} regex A regular expression object or a String.
* Anything else is implicitly converted to
* a String.
* @param {Number} [fromIndex] Optional. The location within the
* calling string to start the search at,
* indexed from left to right. It can be
* any integer. The default value is
* str.length. If it is negative, it is
* treated as 0. If fromIndex > str.length,
* fromIndex is treated as str.length.
* @returns {Number} If successful, returns the index of the first
* match of the regular expression inside the
* string. Otherwise, it returns -1.
*/
$defineProperty(String.prototype, 'searchLastOf', {
enumerable: false,
configurable: true,
writable: true,
value: function (regex) {
var str = $onlyCoercibleToString(this),
args = $toArray(arguments),
result = -1,
fromIndex,
length,
match,
pos,
rx;
if (!$isRegExp(regex)) {
return String.prototype.lastIndexOf.apply(str, args);
}
length = $toLength(str.length);
if (!$strictEqual(args[1], args[1])) {
fromIndex = length;
} else {
if ($toLength(args.length) > 1) {
fromIndex = $toInteger(args[1]);
} else {
fromIndex = length - 1;
}
}
if (fromIndex >= 0) {
fromIndex = Math.min(fromIndex, length - 1);
} else {
fromIndex = length - Math.abs(fromIndex);
}
pos = 0;
rx = $toSearchRegExp(regex);
while (pos <= fromIndex) {
rx.lastIndex = pos;
match = rx.exec(str);
if (!match) {
break;
}
pos = +match.index;
if (pos <= fromIndex) {
result = pos;
}
pos += 1;
}
return result;
}
});
}
}());
(function () {
'use strict';
/*
* testing as follow to make sure that at least for one character regexp,
* the result is the same as if we used indexOf
*/
var pre = document.getElementById('out');
function log(result) {
pre.appendChild(document.createTextNode(result + '\n'));
}
function test(str) {
var i = str.length + 2,
r,
a,
b;
while (i) {
a = str.indexOf('a', i);
b = str.searchOf(/a/, i);
r = ['Failed', 'searchOf', str, i, a, b];
if (a === b) {
r[0] = 'Passed';
}
log(r);
a = str.lastIndexOf('a', i);
b = str.searchLastOf(/a/, i);
r = ['Failed', 'searchLastOf', str, i, a, b];
if (a === b) {
r[0] = 'Passed';
}
log(r);
i -= 1;
}
}
/*
* Look for the a among the xes
*/
test('xxx');
test('axx');
test('xax');
test('xxa');
test('axa');
test('xaa');
test('aax');
test('aaa');
}());
<pre id="out"></pre>
RegExp를 사용하여 매우 간단한 lastIndex 조회를 찾고 lastIndexOf를 마지막 세부 사항과 모방하는지 신경 쓰지 않으면주의를 끌 수 있습니다.
나는 단순히 문자열을 뒤집고 길이-1에서 첫 번째 발생 색인을 뺍니다. 테스트를 통과했지만 긴 문자열에서 성능 문제가 발생할 수 있다고 생각합니다.
interface String {
reverse(): string;
lastIndex(regex: RegExp): number;
}
String.prototype.reverse = function(this: string) {
return this.split("")
.reverse()
.join("");
};
String.prototype.lastIndex = function(this: string, regex: RegExp) {
const exec = regex.exec(this.reverse());
return exec === null ? -1 : this.length - 1 - exec.index;
};
String.prototype.match(regex)
문자열에서 주어진 모든 일치 항목의 문자열 배열을 반환하는 사용했습니다 regex
(자세한 내용은 여기 참조 ).
function getLastIndex(text, regex, limit = text.length) {
const matches = text.match(regex);
// no matches found
if (!matches) {
return -1;
}
// matches found but first index greater than limit
if (text.indexOf(matches[0] + matches[0].length) > limit) {
return -1;
}
// reduce index until smaller than limit
let i = matches.length - 1;
let index = text.lastIndexOf(matches[i]);
while (index > limit && i >= 0) {
i--;
index = text.lastIndexOf(matches[i]);
}
return index > limit ? -1 : index;
}
// expect -1 as first index === 14
console.log(getLastIndex('First Sentence. Last Sentence. Unfinished', /\. /g, 10));
// expect 29
console.log(getLastIndex('First Sentence. Last Sentence. Unfinished', /\. /g));
var mystring = "abc ab a";
var re = new RegExp("ab"); // any regex here
if ( re.exec(mystring) != null ){
alert("matches"); // true in this case
}
표준 정규식을 사용하십시오.
var re = new RegExp("^ab"); // At front
var re = new RegExp("ab$"); // At end
var re = new RegExp("ab(c|d)"); // abc or abd
글쎄, 당신이 캐릭터 의 위치와 일치하기를 원할 때 정규 표현식은 과잉 일 수 있습니다.
나는 당신이 원하는 것은 "이 캐릭터를 먼저 찾아라"는 대신이 캐릭터들 중 첫 번째를 찾는 것 뿐이라고 생각합니다.
이것은 물론 간단한 대답이지만 정규 표현식 부분이 없어도 질문에 명시된 것을 수행합니다 (왜 명시 적으로 정규 표현식 이었는지 명확히하지 않았기 때문입니다)
function mIndexOf( str , chars, offset )
{
var first = -1;
for( var i = 0; i < chars.length; i++ )
{
var p = str.indexOf( chars[i] , offset );
if( p < first || first === -1 )
{
first = p;
}
}
return first;
}
String.prototype.mIndexOf = function( chars, offset )
{
return mIndexOf( this, chars, offset ); # I'm really averse to monkey patching.
};
mIndexOf( "hello world", ['a','o','w'], 0 );
>> 4
mIndexOf( "hello world", ['a'], 0 );
>> -1
mIndexOf( "hello world", ['a','o','w'], 4 );
>> 4
mIndexOf( "hello world", ['a','o','w'], 5 );
>> 6
mIndexOf( "hello world", ['a','o','w'], 7 );
>> -1
mIndexOf( "hello world", ['a','o','w','d'], 7 );
>> 10
mIndexOf( "hello world", ['a','o','w','d'], 10 );
>> 10
mIndexOf( "hello world", ['a','o','w','d'], 11 );
>> -1
'Programing' 카테고리의 다른 글
C void 인수“void foo (void)”를 사용하거나“void foo ()”를 사용하지 않는 것이 더 낫습니까? (0) | 2020.05.09 |
---|---|
Swift에서 사전을 반복 (0) | 2020.05.09 |
지역 지점에서 다른 지점으로 "당기는"방법은 무엇입니까? (0) | 2020.05.09 |
'권장 권장 아이콘 파일-번들에 정확히'120x120 '픽셀의 iPhone / iPod Touch 용 앱 아이콘이 포함되어 있지 않습니다 (.png 형식). (0) | 2020.05.09 |
현지화 및 국제화, 차이점은 무엇입니까? (0) | 2020.05.09 |