Em javascript, existe um equivalente a String.indexOf () que usa uma expressão regular em vez de uma string para o primeiro primeiro parâmetro enquanto ainda permite um segundo parâmetro?
Eu preciso fazer algo como
str.indexOf(/[abc]/ , i);
e
str.lastIndexOf(/[abc]/ , i);
Enquanto String.search () usa uma regexp como parâmetro, ela não me permite especificar um segundo argumento!
Edit:
Isso acabou sendo mais difícil do que eu pensava, então escrevi uma pequena função de teste para testar todas as soluções fornecidas ... pressupõe que regexIndexOf e regexLastIndexOf foram adicionados ao objeto 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)]) ;
}
}
e estou testando a seguir para garantir que pelo menos para uma expressão regular de caracteres, o resultado seja o mesmo que se usássemos indexOf
// Procure o a entre o
teste xes ('xxx');
teste ('axx');
teste ('xax');
teste ('xxa');
teste ('axa');
teste ('xaa');
teste ('aax');
teste ('aaa');
fonte
|
inside[ ]
corresponde ao caractere literal|
. Você provavelmente quis dizer[abc]
.Respostas:
Combinando algumas das abordagens já mencionadas (o indexOf é obviamente bastante simples), acho que estas são as funções que farão o truque:
Obviamente, modificar o objeto String incorporado enviaria sinalizadores vermelhos para a maioria das pessoas, mas pode ser uma vez em que não é grande coisa; simplesmente esteja ciente disso.
ATUALIZAÇÃO: Editado de
regexLastIndexOf()
modo que parece imitarlastIndexOf()
agora. Informe-me se ainda falhar e em que circunstâncias.ATUALIZAÇÃO: passa em todos os testes encontrados nos comentários desta página e nos meus. Claro, isso não significa que é à prova de balas. Qualquer feedback apreciado.
fonte
regexLastIndexOf
retornará apenas o índice da última correspondência sem sobreposição .regex.lastIndex = result.index + 1;
vez deregex.lastIndex = ++nextStop;
. Espera-se que vá para a próxima partida muito mais rápido, sem perder nenhum resultado.Instâncias do
String
construtor têm um.search()
método que aceita um RegExp e retorna o índice da primeira correspondência.Para iniciar a pesquisa a partir de uma posição específica (fingindo o segundo parâmetro de
.indexOf()
), você podeslice
desativar os primeirosi
caracteres:Mas isso fará com que o índice fique na string mais curta (após a primeira parte ter sido cortada), então você desejará adicionar o comprimento da parte cortada (
i
) ao índice retornado, se não estiver-1
. Isso fornecerá o índice na string original:fonte
function regexIndexOf(text, offset) { var initial = text.substr(offset).search(/re/); if(initial >= 0) { initial += offset; } return initial; }
Eu tenho uma versão curta para você. Funciona bem para mim!
E se você quiser uma versão protótipo:
EDIT : se você deseja adicionar suporte para fromIndex
Para usá-lo, simples assim:
fonte
startIndex
parâmetro como de costumeindeoxOf
elastIndexOf
fazer.startIndex
(oufromIndex
). Espero que ajude!lastIndexOfRegex
também deve adicionar novamente o valor defromIndex
ao resultado."aRomeo Romeo".indexOfRegex(new RegExp("\\bromeo", 'gi'));
O resultado será 1 quando deve ser 7, porque o indexOf procurará pela primeira vez o "romeo" aparecer, não importa se está no início de uma palavra ou não.Usar:
Veja a documentação aqui.
fonte
0
, e foi publicada ... sete anos depois.Baseado na resposta de BaileyP. A principal diferença é que esses métodos retornam
-1
se o padrão não puder ser correspondido.Edit: Graças à resposta de Jason Bunting, tive uma idéia. Por que não modificar a
.lastIndex
propriedade do regex? Embora isso funcione apenas para padrões com a bandeira global (/g
).Edit: Atualizado para passar nos casos de teste.
fonte
Você poderia usar substr.
fonte
RexExp
As instâncias já têm uma propriedade lastIndex (se forem globais) e, portanto, o que estou fazendo é copiar a expressão regular, modificá-la levemente para se adequar aos nossos propósitos,exec
inseri-la na string e examinar olastIndex
. Isso inevitavelmente será mais rápido do que dar laços na corda. (Você tem exemplos suficientes de como colocar isso no protótipo de string, certo?)Você também pode criar um protótipo das funções no objeto RegExp:
Uma rápida explicação de como eu estou modificando o
RegExp
: PoisindexOf
eu apenas tenho que garantir que a bandeira global esteja definida. ParalastIndexOf
, estou usando uma observação negativa para encontrar a última ocorrência, a menos queRegExp
já esteja correspondendo no final da string.fonte
Não é nativo, mas você certamente pode adicionar essa funcionalidade
Não testei completamente esses métodos, mas eles parecem funcionar até agora.
fonte
Depois de todas as soluções propostas falharem nos meus testes, de uma maneira ou de outra (editar: algumas foram atualizadas para passar nos testes depois que escrevi isso), encontrei a implementação do mozilla para Array.indexOf e Array.lastIndexOf
Eu os usei para implementar minha versão de String.prototype.regexIndexOf e String.prototype.regexLastIndexOf da seguinte maneira:
Eles parecem passar nas funções de teste que forneci na pergunta.
Obviamente, eles só funcionam se a expressão regular corresponder a um caractere, mas isso é suficiente para o meu objetivo, pois eu a usarei para coisas como ([abc], \ s, \ W, \ D)
Continuarei monitorando a pergunta caso alguém forneça uma implementação melhor / mais rápida / mais limpa / mais genérica que funcione em qualquer expressão regular.
fonte
Eu também precisava de uma
regexIndexOf
função para uma matriz, então programei uma. No entanto, duvido que seja otimizado, mas acho que deve funcionar corretamente.fonte
Em certos casos simples, você pode simplificar sua pesquisa para trás usando divisão.
Isso tem alguns problemas sérios:
Mas o lado positivo é muito menos código. Para um regex de comprimento constante que não pode se sobrepor (como
/\s\w/
para encontrar limites de palavras), isso é bom o suficiente.fonte
Para dados com correspondências esparsas, o uso de string.search é o mais rápido entre os navegadores. Ele divide novamente uma string a cada iteração para:
Para dados densos eu fiz isso. É complexo comparado ao método execute, mas para dados densos, é 2-10x mais rápido do que qualquer outro método que eu tentei e cerca de 100x mais rápido que a solução aceita. Os pontos principais são:
O novo regex é executado e os resultados desse exec ou do primeiro exec são retornados;
jsPerf de métodos
Eu não entendo o propósito dos testes lá em cima. É impossível comparar situações que exigem um regex com uma chamada para indexOf, que eu acho que é o ponto de fazer o método em primeiro lugar. Para que o teste seja aprovado, faz mais sentido usar 'xxx + (?! x)' do que ajustar a maneira como o regex itera.
fonte
O último índice de Jason Bunting não funciona. O meu não é o ideal, mas funciona.
fonte
Ainda não existem métodos nativos que executam a tarefa solicitada.
Aqui está o código que estou usando. Ele imita o comportamento de String.prototype.indexOf e String.prototype.lastIndexOf métodos, mas eles também aceitar um RegExp como o argumento de pesquisa, além de uma cadeia que representa o valor a procurar.
Sim, é bastante longo para responder, pois tenta seguir os padrões atuais o mais próximo possível e, é claro, contém uma quantidade razoável de comentários do JSDOC . No entanto, uma vez minificado, o código tem apenas 2,27k e uma vez compactado para transmissão, tem apenas 1023 bytes.
Os 2 métodos que isso adiciona
String.prototype
(usando Object.defineProperty, quando disponível) são:searchOf
searchLastOf
Ele passa em todos os testes que o OP postou e, adicionalmente, eu testei as rotinas completamente no meu uso diário, e tentei garantir que elas funcionassem em vários ambientes, mas comentários / problemas são sempre bem-vindos.
fonte
Se você estiver procurando uma pesquisa lastIndex muito simples com o RegExp e não se importa se imita lastIndexOf até o último detalhe, isso pode chamar sua atenção.
Simplesmente inverto a string e subtraio o primeiro índice de ocorrência do comprimento - 1. Isso passa no meu teste, mas acho que poderia surgir um problema de desempenho com longas strings.
fonte
Eu usei o
String.prototype.match(regex)
que retorna uma matriz de seqüência de caracteres de todas as correspondências encontradas dos dadosregex
na seqüência de caracteres (mais informações, veja aqui ):fonte
Use expressões regulares padrão:
fonte
Bem, como você está apenas procurando corresponder à posição de um personagem , regex é possivelmente um exagero.
Presumo que tudo o que você quer é que, em vez de "encontrar primeiro esse personagem", encontre primeiro o primeiro.
É claro que essa é a resposta simples, mas faz o que sua pergunta se propõe a fazer, embora sem a parte de regex (porque você não esclareceu por que, especificamente, tinha que ser uma regex)
fonte