Regex pour tout supprimer (période OU non numérique)

93

J'ai besoin d'un texte comme "joe (3 004,50 $)" pour être filtré jusqu'à 3004,50 mais je suis terrible à regex et je ne trouve pas de solution appropriée. Ainsi, seuls les nombres et les périodes doivent rester - tout le reste est filtré. J'utilise C # et VS.net 2008 framework 3.5

Prêt Cent
la source

Réponses:

167

Cela devrait le faire:

string s = "joe ($3,004.50)";
s = Regex.Replace(s, "[^0-9.]", "");
josephj1989
la source
1
Et quoi joe.smith ($3,004.50)? Le simple fait de supprimer les classes de caractères incriminées peut être très faux.
Matthew Gunn
2
Je fais une petite correction: Regex.Replace(s, "[^$0-9.]", "");vous voulez laisser le signe dollar.
bodacydo
35

Le regex est:

[^0-9.]

Vous pouvez mettre en cache l'expression régulière:

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

puis utilisez:

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

Cependant, vous devez garder à l'esprit que certaines cultures ont des conventions différentes pour l'écriture des montants monétaires, telles que: 3.004,50.

Matthew Flaschen
la source
ATM trop paresseux pour vérifier, mais vous n'avez pas besoin d'échapper au fichier. ?
Andrew Anderson
9
@Andrew: non, à l'intérieur d'une classe de caractères, .n'a pas de signification particulière.
Bart Kiers
2

Pour la réponse acceptée, MatthewGunn soulève un point valide en ce que tous les chiffres, virgules et points de la chaîne entière seront condensés ensemble. Cela évitera 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
la source
Semble au-dessus de regex a des parenthèses supplémentaires. L'utilisation (?:^|[^w.,])(\d[\d,.]+)(?=\W|$)correspondra également à "h25" dans la chaîne "joe.smith25 (3 004,50 $)"
Rivka
1

L'approche consistant à supprimer les personnages fautifs est potentiellement problématique. Et s'il y en avait un autre .dans la chaîne quelque part? Il ne sera pas supprimé, bien qu'il le soit!

En supprimant les non-chiffres ou les points, la chaîne joe.smith ($3,004.50)se transformerait en non analysable .3004.50.

Imho, il est préférable de faire correspondre un modèle spécifique et de l'extraire en utilisant un groupe. Quelque chose de simple serait de trouver toutes les virgules, chiffres et points contigus avec l'expression rationnelle:

[\d,\.]+

Exemple de test:

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"

Ensuite, pour chaque correspondance, supprimez toutes les virgules et envoyez-les à l'analyseur. Pour gérer le cas de quelque chose comme 12.323.344, vous pouvez faire une autre vérification pour voir qu'une sous-chaîne correspondante en a au plus une ..

Matthew Gunn
la source
Cette regex correspond à tout.
mindriot
Il correspond maintenant à tout sauf "".
mindriot
1
Le concept que vous proposez nécessiterait une expression régulière complexe qui est difficile à lire et à déboguer. Il peut être préférable de le décomposer en étapes avec plusieurs expressions régulières et conditionnelles. Je pourrais fournir une réponse (bien qu'écrit en Ruby car je ne sais pas c #.
mindriot
@mindriot Point pris. Je l'ai changé pour quelque chose de plus transparent.
Matthew Gunn
Par envoyer à l'analyseur, voulez-vous dire soit Single.Parse()ou Single.TryParse?
mindriot
1

Vous avez affaire à une chaîne - la chaîne est un IEumerable<char>, vous pouvez donc utiliser LINQ:

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

Console.WriteLine(result);   // 3004.50
wb
la source