Remplacer non numérique par une chaîne vide

125

Ajout rapide des exigences dans notre projet. Un champ dans notre base de données pour contenir un numéro de téléphone est configuré pour n'autoriser que 10 caractères. Donc, si je passe "(913) -444-5555" ou autre chose, y a-t-il un moyen rapide d'exécuter une chaîne à travers une sorte de fonction de remplacement spéciale que je peux lui transmettre un jeu de caractères?

Regex?

Matt Dawdy
la source

Réponses:

251

Certainement regex:

string CleanPhone(string phone)
{
    Regex digitsOnly = new Regex(@"[^\d]");   
    return digitsOnly.Replace(phone, "");
}

ou dans une classe pour éviter de recréer l'expression régulière tout le temps:

private static Regex digitsOnly = new Regex(@"[^\d]");   

public static string CleanPhone(string phone)
{
    return digitsOnly.Replace(phone, "");
}

En fonction de vos entrées du monde réel, vous voudrez peut-être une logique supplémentaire pour faire des choses comme supprimer les 1 en tête (pour les longues distances) ou tout ce qui suit un x ou un X (pour les extensions).

Joël Coehoorn
la source
C'est parfait. Ceci n'est utilisé que quelques fois, donc nous n'avons pas besoin de créer une classe, et en ce qui concerne le premier 1, ce n'est pas une mauvaise idée. Mais je pense que je préfère gérer cela au cas par cas, du moins dans ce projet. Merci encore - si je pouvais voter à nouveau, je le ferais.
Matt Dawdy
1
J'attends que quelqu'un publie une version de la méthode d'extension de ceci pour la classe string :)
Joel Coehoorn
@Joel J'ai ajouté la version de la méthode d'extension ci-dessous. Je suppose que les commentaires ne prennent pas en charge le démarquage.
Aaron
13
La note [^\d]peut être simplifiée à\D
pswg
Combiné cette réponse (mise en cache de l'expression régulière dans la classe) avec la méthode d'extension ci-dessous :)
Vincent Vancalbergh
73

Vous pouvez le faire facilement avec regex:

string subject = "(913)-444-5555";
string result = Regex.Replace(subject, "[^0-9]", ""); // result = "9134445555"
CMS
la source
2
J'ai voté pour être une excellente réponse, mais Joel vous a battu. Merci pour la réponse cependant - j'aime vraiment voir la confirmation de plusieurs sources.
Matt Dawdy
@JoSmo Pour être honnête, Joel's peut être converti en une seule ligne assez trivialement. (Mais j'ai aussi voté pour: D)
Mage Xy
40

Vous n'avez pas besoin d'utiliser Regex.

phone = new String(phone.Where(c => char.IsDigit(c)).ToArray())
Usman Zafar
la source
3
Bonne réponse, pourquoi ajouter plus de référence à l'espace de noms RegularExpressions
BTE
1
@BTE parce que c'est une main courte qui utilise simplementsystem.linq;
Eric Milliot-Martinez
1
Dans quelle mesure cela fonctionne-t-il par rapport à la solution Regex?
Shavais
2
L'ajout d'un test au code de référence de @ Max-PC pour la solution LINQ se traduit par - StringBuilder: 273ms, Regex: 2096ms, LINQ: 658ms. Plus lent que StringBuilder mais toujours nettement plus rapide que Regex. Étant donné qu'il s'agit de comparer 1 000 000 de remplacements, la différence effective entre les solutions StringBuilder et LINQ pour la plupart des scénarios est probablement négligeable.
Chris Pratt
@ChrisPratt pour la regex, avez-vous créé une nouvelle regex à chaque fois, ou ré-utilisé une existante? Cela pourrait avoir un impact important sur les performances.
carlin.scott le
23

Voici la méthode d'extension pour le faire.

public static class Extensions
{
    public static string ToDigitsOnly(this string input)
    {
        Regex digitsOnly = new Regex(@"[^\d]");
        return digitsOnly.Replace(input, "");
    }
}
Aaron
la source
8

En utilisant les méthodes Regex dans .NET, vous devriez pouvoir faire correspondre n'importe quel chiffre non numérique en utilisant \ D, comme ceci:

phoneNumber  = Regex.Replace(phoneNumber, "\\D", String.Empty);
Wes Mason
la source
5
Ce n'est pas tout à fait vrai. Vous avez besoin d'un @ ou d'un "\\ D" pour échapper au \ dans l'expression régulière. Aussi, vous devriez utiliser String.Empty au lieu de ""
Bryan
5

Que diriez-vous d'une méthode d'extension qui n'utilise pas regex.

Si vous vous en tenez à l'une des options Regex, utilisez au moins RegexOptions.Compiledla variable statique.

public static string ToDigitsOnly(this string input)
{
    return new String(input.Where(char.IsDigit).ToArray());
}

Cela s'appuie sur la réponse d'Usman Zafar convertie en groupe de méthodes.

Michael Lang
la source
4

pour obtenir les meilleures performances et réduire la consommation de mémoire, essayez ceci:

using System;
using System.Diagnostics;
using System.Text;
using System.Text.RegularExpressions;

public class Program
{
    private static Regex digitsOnly = new Regex(@"[^\d]");

    public static void Main()
    {
        Console.WriteLine("Init...");

        string phone = "001-12-34-56-78-90";

        var sw = new Stopwatch();
        sw.Start();
        for (int i = 0; i < 1000000; i++)
        {
            DigitsOnly(phone);
        }
        sw.Stop();
        Console.WriteLine("Time: " + sw.ElapsedMilliseconds);

        var sw2 = new Stopwatch();
        sw2.Start();
        for (int i = 0; i < 1000000; i++)
        {
            DigitsOnlyRegex(phone);
        }
        sw2.Stop();
        Console.WriteLine("Time: " + sw2.ElapsedMilliseconds);

        Console.ReadLine();
    }

    public static string DigitsOnly(string phone, string replace = null)
    {
        if (replace == null) replace = "";
        if (phone == null) return null;
        var result = new StringBuilder(phone.Length);
        foreach (char c in phone)
            if (c >= '0' && c <= '9')
                result.Append(c);
            else
            {
                result.Append(replace);
            }
        return result.ToString();
    }

    public static string DigitsOnlyRegex(string phone)
    {
        return digitsOnly.Replace(phone, "");
    }
}

Le résultat sur mon ordinateur est:
Init ...
Heure: 307
Heure: 2178

Max-PC
la source
+1 pour afficher des repères. Il est intéressant de noter que la boucle avec StringBuilder surpasse RegEx, bien que je suppose que cela a du sens quand RegEx doit probablement parcourir de nombreuses règles pour décider quoi faire.
Steve In CO
3

Je suis sûr qu'il existe un moyen plus efficace de le faire, mais je le ferais probablement:

string getTenDigitNumber(string input)
{    
    StringBuilder sb = new StringBuilder();
    for(int i - 0; i < input.Length; i++)
    {
        int junk;
        if(int.TryParse(input[i], ref junk))
            sb.Append(input[i]);
    }
    return sb.ToString();
}
Jon Norton
la source
C'était mon premier instinct, et c'est aussi pourquoi j'ai demandé ici. RegEx me semble être une bien meilleure solution. Mais merci pour la réponse!
Matt Dawdy
-1

essaye ça

public static string cleanPhone(string inVal)
        {
            char[] newPhon = new char[inVal.Length];
            int i = 0;
            foreach (char c in inVal)
                if (c.CompareTo('0') > 0 && c.CompareTo('9') < 0)
                    newPhon[i++] = c;
            return newPhon.ToString();
        }
Charles Bretana
la source
return newPhone.ToString();renverra "System.Char []". Je pense que vous vouliez dire return new string(newPhone);, mais c'est aussi filtrer les nombres 0 et 9 à cause de >et <au lieu de >=et <=. Mais même dans ce cas, la chaîne aura des espaces à la fin car le newPhontableau est plus long que nécessaire.
juharr