Regex para eliminar todo (punto O no numérico)

95

Necesito que un texto como "joe ($ 3,004.50)" se filtre a 3004.50 pero soy terrible con las expresiones regulares y no puedo encontrar una solución adecuada. Por lo tanto, solo deben permanecer los números y los puntos, todo lo demás filtrado. Yo uso C # y VS.net 2008 framework 3.5

Listo Cent
fuente

Respuestas:

168

Esto debería hacerlo:

string s = "joe ($3,004.50)";
s = Regex.Replace(s, "[^0-9.]", "");
josephj1989
fuente
1
¿Qué hay de joe.smith ($3,004.50)? Simplemente eliminar las clases de personajes ofensivos puede salir mal.
Matthew Gunn
2
Hago una pequeña corrección: Regex.Replace(s, "[^$0-9.]", "");quieres dejar el signo del dólar.
bodacydo
36

La expresión regular es:

[^0-9.]

Puede almacenar en caché la expresión regular:

Regex not_num_period = new Regex("[^0-9.]")

luego usa:

string result = not_num_period.Replace("joe ($3,004.50)", "");

Sin embargo, debe tener en cuenta que algunas culturas tienen diferentes convenciones para escribir cantidades monetarias, como: 3.004,50.

Matthew Flaschen
fuente
Cajero automático demasiado perezoso para verificar, pero no necesita escapar del. ?
Andrew Anderson
9
@Andrew: no, dentro de una clase de carácter, .no tiene un significado especial.
Bart Kiers
2

Para la respuesta aceptada, MatthewGunn plantea un punto válido en el sentido de que todos los dígitos, comas y puntos de toda la cadena se condensarán. Esto evitará que:

string s = "joe.smith ($3,004.50)";
Regex r = new Regex(@"(?:^|[^w.,])(\d[\d,.]+)(?=\W|$)/)");
Match m = r.match(s);
string v = null;
if (m.Success) {
  v = m.Groups[1].Value;
  v = Regex.Replace(v, ",", "");
}
Mindriot
fuente
Parece que la expresión regular anterior tiene paréntesis extra. El uso (?:^|[^w.,])(\d[\d,.]+)(?=\W|$)también coincidirá con "h25" en la cadena "joe.smith25 ($ 3,004.50)"
Rivka
1

El enfoque de eliminar personajes ofensivos es potencialmente problemático. ¿Qué pasa si hay otro .en la cuerda en alguna parte? ¡No se eliminará, aunque debería!

Al eliminar los no dígitos o puntos, la cadena joe.smith ($3,004.50)se transformaría en lo que no se puede analizar .3004.50.

En mi humilde opinión, es mejor hacer coincidir un patrón específico y extraerlo usando un grupo. Algo simple sería encontrar todas las comas, dígitos y puntos contiguos con regexp:

[\d,\.]+

Ejecución de prueba de muestra:

Pattern understood as:
[\d,\.]+
Enter string to check if matches pattern
>  a2.3 fjdfadfj34  34j3424  2,300 adsfa    
Group 0 match: "2.3"
Group 0 match: "34"
Group 0 match: "34"
Group 0 match: "3424"
Group 0 match: "2,300"

Luego, para cada coincidencia, elimine todas las comas y envíelo al analizador. Para manejar el caso de algo como 12.323.344, podría hacer otra verificación para ver que una subcadena coincidente tenga como máximo una ..

Matthew Gunn
fuente
Esta expresión regular coincide con todo.
Mindriot
Ahora coincide con todo excepto "".
Mindriot
1
El concepto que propones requeriría una expresión regular compleja que sea difícil de leer y depurar. Puede ser mejor dividirlo en pasos con varias expresiones regulares y condicionales. Podría proporcionar una respuesta (aunque está escrito en Ruby, ya que no sé c #.)
mindriot
@mindriot Punto tomado. Lo cambié por algo más transparente.
Matthew Gunn
Por enviar al analizador, ¿te refieres a Single.Parse()o Single.TryParse?
Mindriot
1

Está tratando con una cadena, la cadena es una IEumerable<char>, por lo que puede usar LINQ:

var input = "joe ($3,004.50)";
var result = String.Join("", input.Where(c => Char.IsDigit(c) || c == '.'));

Console.WriteLine(result);   // 3004.50
wb
fuente