regex - numeros - expresiones regulares c#
Una expresión regular para el análisis del número de versión (19)
¡Gracias por todas las respuestas! Esto es as :)
Basado en la respuesta de OneByOne (que me pareció la más simple), agregué algunos grupos que no capturan (las partes ''(?:'' - gracias a VonC por presentarme a grupos que no capturan), por lo que los grupos que capturan solo contener los dígitos o el carácter *.
^(?:(/d+)/.)?(?:(/d+)/.)?(/*|/d+)$
¡Muchas gracias a todos!
Tengo un número de versión de la siguiente forma:
version.release.modification
donde la versión, la versión y la modificación son un conjunto de dígitos o el carácter comodín ''*''. Además, puede faltar cualquiera de estos números (y cualquier otro anterior).
Entonces los siguientes son válidos y analizan como:
1.23.456 = version 1, release 23, modification 456
1.23 = version 1, release 23, any modification
1.23.* = version 1, release 23, any modification
1.* = version 1, any release, any modification
1 = version 1, any release, any modification
* = any version, any release, any modification
Pero estos no son válidos:
*.12
*123.1
12*
12.*.34
¿Alguien puede proporcionarme una expresión regular no demasiado compleja para validar y recuperar los números de lanzamiento, versión y modificación?
Especificando elementos XSD:
<xs:simpleType>
<xs:restriction base="xs:string">
<xs:pattern value="[0-9]{1,3}/.[0-9]{1,3}/.[0-9]{1,3}(/..*)?"/>
</xs:restriction>
</xs:simpleType>
Esto coincide con 1.2.3. * También
^ (* | / d + (. / d +) {0,2} (. *)?) $
Yo propondría lo menos elegante:
(* | / d + (. / d +)? (. *)?) | / d +. / d +. / d +)
Esto debería funcionar para lo que estipulaste. Se basa en la posición comodín y es una expresión regular anidada:
^((/*)|([0-9]+(/.((/*)|([0-9]+(/.((/*)|([0-9]+)))?)))?))$
Esto podría funcionar:
^(/*|/d+(/./d+){0,2}(/./*)?)$
En el nivel superior, "*" es un caso especial de un número de versión válido. De lo contrario, comienza con un número. Luego hay cero, uno o dos secuencias ".nn", seguidas de un ". *" Opcional. Esta expresión regular aceptaría 1.2.3. * Que puede o no estar permitido en su aplicación.
El código para recuperar las secuencias coincidentes, especialmente la parte (/./d+){0,2}
, dependerá de su biblioteca de expresiones regulares particular.
Expresaría el formato como:
"1-3 componentes separados por punto, cada número excepto que el último puede ser *"
Como una expresión regular, eso es:
^(/d+/.)?(/d+/.)?(/*|/d+)$
[Editar para agregar: esta solución es una forma concisa de validar, pero se ha señalado que la extracción de los valores requiere un trabajo adicional. Es una cuestión de gusto tratar esto complicando la expresión regular, o procesando los grupos coincidentes.
En mi solución, los grupos capturan el "."
caracteres. Esto se puede tratar utilizando grupos no capturadores como en la respuesta de ajborley.
Además, el grupo de la derecha capturará el último componente, incluso si hay menos de tres componentes, por lo que, por ejemplo, una entrada de dos componentes da como resultado la captura del primer y último grupo y el del medio no definido. Creo que esto puede ser tratado por grupos no codiciosos donde sea compatible.
El código Perl para tratar ambos problemas después de la expresión regular podría ser algo como esto:
@version = ();
@groups = ($1, $2, $3);
foreach (@groups) {
next if !defined;
s//.//;
push @version, $_;
}
($major, $minor, $mod) = (@version, "*", "*");
Que en realidad no es más corto que dividir en "."
]
He visto muchas respuestas, pero ... tengo una nueva. Funciona para mí al menos. He agregado una nueva restricción. Los números de versión no pueden comenzar (mayor, menor o parche) con ceros seguidos por otros.
01.0.0 no es válido 1.0.0 es válido 10.0.10 es válido 1.0.0000 no es válido
^(?:(0//.|([1-9]+//d*)//.))+(?:(0//.|([1-9]+//d*)//.))+((0|([1-9]+//d*)))$
Está basado en uno anterior. Pero veo esta solución mejor ... para mí;)
¡¡¡Disfrutar!!!
Mi opinión sobre esto, como un buen ejercicio - vparse , que tiene una fuente pequeña , con una función simple:
function parseVersion(v) {
var m = v.match(//d*/.|/d+/g) || [];
v = {
major: +m[0] || 0,
minor: +m[1] || 0,
patch: +m[2] || 0,
build: +m[3] || 0
};
v.isEmpty = !v.major && !v.minor && !v.patch && !v.build;
v.parsed = [v.major, v.minor, v.patch, v.build];
v.text = v.parsed.join(''.'');
return v;
}
Mis 2 centavos: tuve este escenario: tuve que analizar los números de versión de un literal de cadena. (Sé que esto es muy diferente de la pregunta original, pero buscar en Google para encontrar una expresión regular para analizar el número de versión mostró este hilo en la parte superior, por lo que agrego esta respuesta aquí)
Entonces, el literal de cadena sería algo así como: "¡Se está ejecutando la versión de servicio 1.2.35.564!"
Tuve que analizar el 1.2.35.564 fuera de este literal. Siguiendo el ejemplo de @ajborley, mi expresión regular es la siguiente:
(?:(/d+)/.)?(?:(/d+)/.)?(?:(/d+)/./d+)
Un pequeño fragmento de C # para probar esto se ve a continuación:
void Main()
{
Regex regEx = new Regex(@"(?:(/d+)/.)?(?:(/d+)/.)?(?:(/d+)/./d+)", RegexOptions.Compiled);
Match version = regEx.Match("The Service SuperService 2.1.309.0) is Running!");
version.Value.Dump("Version using RegEx"); // Prints 2.1.309.0
}
No sé en qué plataforma está, pero en .NET está la clase System.Version que analizará los números de versión "nnnn" por usted.
Otro intento:
^(((/d+)/.)?(/d+)/.)?(/d+|/*)$
Esto da las tres partes en grupos 4,5,6 PERO: Están alineados a la derecha. Así que el primer no nulo de 4,5 o 6 da el campo de versión.
- 1.2.3 da 1,2,3
- 1.2. * Da 1,2, *
- 1.2 da nulo, 1,2
- *** da nulo, nulo, *
- 1. * da nulo, 1, *
Parece bastante difícil tener una expresión regular que hace exactamente lo que desea (es decir, acepta solo los casos que necesita y rechaza todos los demás y devuelve algunos grupos para los tres componentes). Lo intenté y presenté esto:
^(/*|(/d+(/.(/d+(/.(/d+|/*))?|/*))?))$
IMO (no he probado ampliamente) esto debería funcionar bien como un validador para la entrada, pero el problema es que esta expresión regular no ofrece una forma de recuperar los componentes. Para eso, todavía tienes que hacer un split en el período.
Esta solución no es todo en uno, pero la mayoría de las veces en la programación no es necesario. Por supuesto, esto depende de otras restricciones que pueda tener en su código.
Tenía un requisito para buscar / combinar números de versión, que sigue la convención de maven o incluso solo un dígito. Pero no califica en ningún caso. Fue peculiar, me llevó tiempo, entonces se me ocurrió esto:
''^[0-9][0-9.]*$''
Esto asegura que la versión,
- Comienza con un dígito
- Puede tener cualquier cantidad de dígitos
- Solo dígitos y ''.'' están permitidos
Un inconveniente es que la versión puede incluso terminar con ''.'' Pero puede manejar una duración indefinida de la versión (versiones locas si quieres llamarlo así)
Partidos:
- 1.2.3
- 1.09.5
- 3.4.4.5.7.8.8.
- 23.6.209.234.3
Si no está satisfecho con ''.'' terminando, puede ser que puedas combinar con endswith logic
Tenga en cuenta que los regexp son codiciosos, por lo que si solo está buscando en la cadena del número de versión y no en un texto más grande, use ^ y $ para marcar el inicio y el final de la cadena. La expresión regular de Greg parece funcionar bien (solo le di un rápido intento en mi editor), pero dependiendo de tu biblioteca / idioma, la primera parte aún puede coincidir con el "*" dentro de los números de versión incorrectos. Tal vez me esté perdiendo algo, ya que no he usado Regexp durante un año más o menos.
Esto debería asegurarse de que solo pueda encontrar los números de versión correctos:
^ (/ * | / d + (/. / d +) * (/. / *)?) $
editar: en realidad, Greg ya los agregó y hasta mejoró su solución, soy demasiado lento :)
Tiendo a estar de acuerdo con la sugerencia dividida.
He creado un "probador" para su problema en perl
#!/usr/bin/perl -w
@strings = ( "1.2.3", "1.2.*", "1.*","*" );
%regexp = ( svrist => qr/(?:(/d+)/.(/d+)/.(/d+)|(/d+)/.(/d+)|(/d+))?(?:/./*)?/,
onebyone => qr/^(/d+/.)?(/d+/.)?(/*|/d+)$/,
greg => qr/^(/*|/d+(/./d+){0,2}(/./*)?)$/,
vonc => qr/^((?:/d+(?!/./*)/.)+)(/d+)?(/./*)?$|^(/d+)/./*$|^(/*|/d+)$/,
ajb => qr/^(?:(/d+)/.)?(?:(/d+)/.)?(/*|/d+)$/,
jrudolph => qr/^(((/d+)/.)?(/d+)/.)?(/d+|/*)$/
);
foreach my $r (keys %regexp){
my $reg = $regexp{$r};
print "Using $r regexp/n";
foreach my $s (@strings){
print "$s : ";
if ($s =~m/$reg/){
my ($main, $maj, $min,$rev,$ex1,$ex2,$ex3) = ("any","any","any","any","any","any","any");
$main = $1 if ($1 && $1 ne "*") ;
$maj = $2 if ($2 && $2 ne "*") ;
$min = $3 if ($3 && $3 ne "*") ;
$rev = $4 if ($4 && $4 ne "*") ;
$ex1 = $5 if ($5 && $5 ne "*") ;
$ex2 = $6 if ($6 && $6 ne "*") ;
$ex3 = $7 if ($7 && $7 ne "*") ;
print "$main $maj $min $rev $ex1 $ex2 $ex3/n";
}else{
print " nomatch/n";
}
}
print "------------------------/n";
}
Salida de corriente:
> perl regex.pl
Using onebyone regexp
1.2.3 : 1. 2. 3 any any any any
1.2.* : 1. 2. any any any any any
1.* : 1. any any any any any any
* : any any any any any any any
------------------------
Using svrist regexp
1.2.3 : 1 2 3 any any any any
1.2.* : any any any 1 2 any any
1.* : any any any any any 1 any
* : any any any any any any any
------------------------
Using vonc regexp
1.2.3 : 1.2. 3 any any any any any
1.2.* : 1. 2 .* any any any any
1.* : any any any 1 any any any
* : any any any any any any any
------------------------
Using ajb regexp
1.2.3 : 1 2 3 any any any any
1.2.* : 1 2 any any any any any
1.* : 1 any any any any any any
* : any any any any any any any
------------------------
Using jrudolph regexp
1.2.3 : 1.2. 1. 1 2 3 any any
1.2.* : 1.2. 1. 1 2 any any any
1.* : 1. any any 1 any any any
* : any any any any any any any
------------------------
Using greg regexp
1.2.3 : 1.2.3 .3 any any any any any
1.2.* : 1.2.* .2 .* any any any any
1.* : 1.* any .* any any any any
* : any any any any any any any
------------------------
Una solución más:
^[1-9][/d]*(.[1-9][/d]*)*(./*)?|/*$
Usa expresiones regulares y ahora tienes dos problemas. Dividiría la cosa en puntos ("."), Luego me aseguraré de que cada parte sea un comodín o un conjunto de dígitos (la expresión regular es perfecta ahora). Si la cosa es válida, solo devuelve el fragmento correcto de la división.
(?ms)^((?:/d+(?!/./*)/.)+)(/d+)?(/./*)?$|^(/d+)/./*$|^(/*|/d+)$
Coincide exactamente con los 6 primeros ejemplos y rechaza los otros 4
- grupo 1: major o major.minor o ''*''
- grupo 2 si existe: menor o *
- grupo 3 si existe: *
Puedes eliminar ''(? Ms)''
Lo usé para indicar a esta QuickRex que se aplicará en líneas múltiples a través de QuickRex
^(?:(/d+)/.)?(?:(/d+)/.)?(/*|/d+)$
Quizás uno más conciso podría ser:
^(?:(/d+)/.){0,2}(/*|/d+)$
Esto se puede mejorar a 1.2.3.4.5. * O restringido exactamente a XYZ usando * o {2} en lugar de {0,2}