Qual é a importância do Pattern.compile()
método?
Por que preciso compilar a string regex antes de obter o Matcher
objeto?
Por exemplo :
String regex = "((\\S+)\\s*some\\s*";
Pattern pattern = Pattern.compile(regex); // why do I need to compile
Matcher matcher = pattern.matcher(text);
new Pattern(regex)
vez de uma função de compilação estática. O comentário de marcolopes está no local.Respostas:
O
compile()
método é sempre chamado em algum ponto; é a única maneira de criar um objeto Padrão. Portanto, a questão é: por que você deveria chamá-lo explicitamente ? Um motivo é que você precisa de uma referência ao objeto Matcher para poder usar seus métodos, comogroup(int)
recuperar o conteúdo de grupos de captura. A única maneira de obter o objeto Matcher é por meio domatcher()
método do objeto Pattern , e a única maneira de obter o objeto Pattern é por meio docompile()
método. Depois, há ofind()
método que, ao contráriomatches()
, não é duplicado nas classes String ou Pattern.A outra razão é evitar criar o mesmo objeto Padrão repetidamente. Cada vez que você usa um dos métodos baseados em regex em String (ou o
matches()
método estático em Pattern), ele cria um novo Pattern e um novo Matcher. Portanto, este snippet de código:... é exatamente equivalente a isto:
Obviamente, isso está fazendo um trabalho desnecessário. Na verdade, pode facilmente levar mais tempo para compilar a regex e instanciar o objeto Pattern do que para realizar uma correspondência real. Portanto, geralmente faz sentido retirar essa etapa do loop. Você também pode criar o Matcher com antecedência, embora eles não sejam tão caros:
Se você está familiarizado com regexes do .NET, pode estar se perguntando se o
compile()
método do Java está relacionado aoRegexOptions.Compiled
modificador do .NET ; a resposta é não. OPattern.compile()
método Java é meramente equivalente ao construtor Regex do .NET. Quando você especifica aCompiled
opção:... ele compila o regex diretamente para o código de byte CIL, permitindo um desempenho muito mais rápido, mas a um custo significativo no processamento inicial e no uso de memória - pense nisso como esteróides para regexes. Java não tem equivalente; não há diferença entre um padrão criado nos bastidores
String#matches(String)
e outro com o qual você cria explicitamentePattern#compile(String)
.(EDITAR: Eu disse originalmente que todos os objetos .NET Regex são armazenados em cache, o que é incorreto. Desde .NET 2.0, o armazenamento em cache automático ocorre apenas com métodos estáticos como
Regex.Matches()
, não quando você chama um construtor Regex diretamente. Ref )fonte
reset
um objeto Matcher que só é usado por um encadeamento por vez para reduzir as alocações.Compile analisa a expressão regular e constrói uma representação na memória . A sobrecarga para compilar é significativa em comparação com uma correspondência. Se você estiver usando um padrão repetidamente, ele obterá algum desempenho para armazenar em cache o padrão compilado.
fonte
Quando você compila, o
Pattern
Java faz alguns cálculos para tornarString
mais rápida a localização de correspondências em s. (Constrói uma representação na memória do regex)Se você for reutilizar
Pattern
várias vezes, verá um grande aumento de desempenho em relação à criação de um novo aPattern
cada vez.No caso de usar o Padrão apenas uma vez, a etapa de compilação parece apenas uma linha extra de código, mas, na verdade, pode ser muito útil no caso geral.
fonte
Matcher matched = Pattern.compile(regex).matcher(text);
. Há vantagens nisso em relação à introdução de um único método: os argumentos são efetivamente nomeados e é óbvio como fatorar oPattern
para melhor desempenho (ou dividir os métodos).É questão de desempenho e uso de memória, compilar e manter o padrão cumprido se precisar usá-lo muito. Um uso típico de regex é validar a entrada do usuário (formatar) e também formatar os dados de saída para os usuários , nessas classes, salvando o padrão cumprido, parece bastante lógico, já que costumam chamar muito.
Abaixo está um validador de exemplo, que realmente é muito chamado :)
Conforme mencionado por @Alan Moore, se você tiver regex reutilizável em seu código (antes de um loop, por exemplo), você deve compilar e salvar o padrão para reutilização.
fonte
Pattern.compile()
permite reutilizar uma regex várias vezes (é threadsafe). O benefício de desempenho pode ser bastante significativo.Fiz uma avaliação rápida:
compileOnce foi entre 3x e 4x mais rápido . Acho que depende muito da própria regex, mas para uma regex que é usada com frequência, procuro um
static Pattern pattern = Pattern.compile(...)
fonte
A pré-compilação do regex aumenta a velocidade. Reutilizar o Matcher oferece outra ligeira aceleração. Se o método for chamado frequentemente, digamos que seja chamado dentro de um loop, o desempenho geral certamente aumentará.
fonte
Semelhante a 'Pattern.compile', há 'RECompiler.compile' [de com.sun.org.apache.regexp.internal] onde:
1. código compilado para o padrão [az] tem 'az' nele
2. código compilado para padrão [0-9] tem '09' nele
3. código compilado para o padrão [abc] tem 'aabbcc' nele.
Assim, o código compilado é uma ótima maneira de generalizar vários casos. Assim, em vez de ter diferentes situações de manipulação de código 1,2 e 3. O problema se reduz à comparação com o ascii do elemento presente e do próximo no código compilado, daí os pares. Portanto,
a. qualquer coisa com ascii entre a e z está entre a e z
b. qualquer coisa com ascii entre 'a e a é definitivamente' a '
fonte
A classe de padrão é o ponto de entrada do mecanismo regex. Você pode usá-la por meio de Pattern.matches () e Pattern.comiple (). #Diferença entre esses dois. Match () - para verificar rapidamente se um texto (String) corresponde a uma dada expressão regular comiple () - cria a referência de Pattern. Portanto, pode usar várias vezes para comparar a expressão regular com vários textos.
Para referência:
fonte