c# - online - regex operators
Por qué ^*$ coincide con "127.0.0.1" (7)
No entiendo, ¿por qué la siguiente expresión regular:
^*$
Coincide con la cadena "127.0.0.1"? Usando Regex.IsMatch("127.0.0.1", "^*$");
Usando Expresso, no coincide, que también es lo que esperaría. Usar la expresión ^.*$
No concuerda con la cadena, lo que también esperaría.
Técnicamente, ^*$
debe coincidir con el comienzo de una cadena / línea cualquier número de veces, seguido por el final de la cadena / línea. Parece * se trata implícitamente como a .*
¿Qué me estoy perdiendo?
EDITAR: ejecuta lo siguiente para ver un ejemplo del problema.
using System;
using System.Text.RegularExpressions;
namespace RegexFubar
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine(Regex.IsMatch("127.0.0.1", "^*$"));
Console.Read();
}
}
}
No deseo que ^ * $ coincida con mi cadena, me pregunto por qué coincide con ella. Creo que la expresión debería dar como resultado una excepción lanzada, o al menos una falta de coincidencia.
EDIT2: para aclarar cualquier confusión. No escribí esta expresión regular con la intención de hacer que coincida con "127.0.0.1". Un usuario de nuestra aplicación ingresó la expresión y se preguntó por qué coincidía con la cadena cuando no debería. Después de mirarlo, no pude encontrar una explicación de por qué coincidía, especialmente no desde Expresso y .NET parece manejarlo de manera diferente.
Supongo que la pregunta se responde porque se debe a la implementación de .NET que evita arrojar una excepción, incluso aunque técnicamente sea una expresión incorrecta. Pero, ¿esto es realmente lo que queremos?
Asterisk (*) coincide con el elemento anterior CERO O MÁS veces. Si quiere uno o más, use el operador + en lugar del *.
Le está pidiendo que haga coincidir un inicio opcional del marcador de cadena y el final del marcador de cadena. Es decir, si omitimos el inicio del marcador de cuerda, solo está buscando el final del marcador de cuerda ... ¡que coincidirá con cualquier cuerda!
Realmente no entiendo lo que estás tratando de hacer. Si pudiera darnos más información, entonces quizás podría decirle lo que debería haber hecho :)
Bueno, teóricamente tienes razón, no debería coincidir. Pero esto depende de cómo funciona la implementación internamente. La mayoría de las expresiones implícitas tomará su expresión regular y tira ^ desde el frente (teniendo en cuenta que debe coincidir desde el comienzo de la cadena) y tira $ desde el final (teniendo en cuenta que debe hacerlo hasta el final de la cadena), lo que sobra es solo "* "y" * "en sí mismo es una expresión regular válida. La implementación que está utilizando es simplemente incorrecta con respecto a cómo manejarla. Podría intentar lo que sucede si reemplaza "^ * $" solo con "*"; Supongo que también coincidirá con todo. Parece que la implementación trata un solo asterisco como ". *".
De acuerdo con la norma ISO / IEC 9945-2: 1993, que también se describe en el estándar POSIX , está roto. Está roto porque el estándar dice que después de un carácter ^, un asterisco no tiene ningún significado especial. Eso significa que "^ * $" solo debería coincidir con una sola cadena y esta cadena es "*" .
Para citar el estándar:
El asterisco es especial excepto cuando se usa:
- en una expresión de corchete
- como el primer personaje de un BRE completo (después de un inicial ^, si lo hay)
- como el primer carácter de una subexpresión (después de una inicial ^, si hay alguna); ver BREs que coinciden con varios personajes.
Entonces, si es el primer personaje (y ^ no cuenta como primer personaje si está presente) no tiene ningún significado especial. Eso significa que en este caso un asterisco solo debe coincidir con un carácter y eso es un asterisco.
Actualizar
Dice Microsoft
Las expresiones regulares de Microsoft .NET Framework incorporan las características más populares de otras implementaciones de expresiones regulares como las de Perl y awk. Diseñadas para ser compatibles con las expresiones regulares de Perl 5, las expresiones regulares de .NET Framework incluyen características que aún no se han visto en otras implementaciones, como la coincidencia de derecha a izquierda y la compilación sobre la marcha.
Fuente: http://msdn.microsoft.com/en-us/library/hs600312.aspx
De acuerdo, probemos esto:
# echo -n 127.0.0.1 | perl -n -e ''print (($_ =~ m/(^.*$)/)[0]),"/n";''
-> 127.0.0.1
# echo -n 127.0.0.1 | perl -n -e ''print (($_ =~ m/(^*$)/)[0]),"/n";''
->
No, no es así. Perl funciona correctamente. ^. * $ coincide con la cadena, ^ * $ does not =>. La implementación de expresiones regulares de .NET está rota y no funciona como Perl 5 como afirma MS.
El estándar de expresiones regulares POSIX es realmente antiguo y limitado. Las pocas herramientas que todavía lo siguen hoy en día, como grep, sed y friends, se encuentran principalmente en un shell de Unix / Linux. Perl y PCRE son dos sabores muy extendidos, en los que casi nada mencionado en el estándar POSIX sigue siendo cierto.
http://www.regular-expressions.info/refflavors.html
En PCRE y Perl, el motor trata ^
y $
como fichas que coinciden con el principio y el final de la cadena (o línea si está configurado el indicador de línea múltiple). *
simplemente repite el ^
marcador cero o más veces (en este caso, exactamente cero veces). Por lo tanto, el motor solo busca el final de la cadena fuente, que coincide con cualquier cadena.
En realidad está diciendo "hacer coincidir una cadena que no contiene nada o nada". Así que va a coincidir. Las vinculaciones ^ y $ realmente no hacen la diferencia en este caso.
La expresión regular ilegal aparte, lo que quieres escribir probablemente no sea eso.
Usted escribe: "^ * $ debe coincidir con el comienzo de una cadena / línea cualquier número de veces, seguido por el final de la cadena / línea", lo que implica que quiere expresiones regulares multilínea, pero se olvida que una línea no puede comenzar dos veces, sin un final de línea entremedio.
Además, lo que está pidiendo en sus requisitos en realidad se ajusta a "127.0.0.1" :) Un "^" no es un salto de línea / retorno de carro sino también el comienzo de una línea, y "$" no es solo una nueva línea sino el fin de una linea
Además, la coincidencia de "*" es tanto como sea posible (excepto cuando se establece un modo no codificado), lo que significa que la expresión regular /^.**$/ regexp coincidirá con todo. Si desea administrar nuevas líneas, debe codificarlas explícitamente.
Espero que esto aclare algo :)
Si intentas
Regex.Match("127.0.0.1", "^*1$")
Verás que también coincide. La propiedad Match.Index tiene un valor de 8, lo que significa que coincide con el último ''1'', no con el primero. Tiene sentido, porque "^ *" coincidirá con cero o más líneas de principio y no hay comienzo de línea cero antes de "1".
Piense en la forma en que "a * 1 $" coincidiría porque no hay ''a'' antes de "1 $". Entonces, "a * $" coincidiría con el final de la línea, como lo hace tu ejemplo.
Por cierto, los documentos de MSDN no mencionan que ''*'' coincida simplemente con ''*'' excepto cuando se escape como ''/ *''. Y ''*'' solo lanzará una excepción, no coincide con ''*''.
Usando RegexDesigner , puedo ver que se está combinando en un token ''nulo'' después de ''127.0.0.1''. Parece que debido a que no ha especificado un token y el signo más coincide con cero o más veces, coincide con el token ''nulo''.
La siguiente expresión regular debería funcionar:
^+$