Sostituisci non numerico con stringa vuota


125

Aggiunta rapida ai requisiti nel nostro progetto. Un campo nel nostro DB per contenere un numero di telefono è impostato per consentire solo 10 caratteri. Quindi, se mi viene superato "(913) -444-5555" o qualcos'altro, esiste un modo rapido per eseguire una stringa attraverso una sorta di funzione di sostituzione speciale che posso passare un set di caratteri per consentire?

Regex?

Risposte:


251

Sicuramente regex:

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

o all'interno di una classe per evitare di ricreare continuamente la regex:

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

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

A seconda degli input del mondo reale, potresti volere qualche logica aggiuntiva lì per fare cose come eliminare 1 in testa (per lunghe distanze) o qualsiasi cosa trascini una x o una X (per le estensioni).


È perfetto. Questo è usato solo un paio di volte, quindi non abbiamo bisogno di creare una classe, e per quanto riguarda il primo, non è una cattiva idea. Ma penso che preferirei gestirlo caso per caso, almeno in questo progetto. Grazie ancora - se potessi votare di nuovo, lo farei.
Matt Dawdy,

1
Sto aspettando che qualcuno pubblichi una versione di questo metodo di estensione per la classe di stringhe :)
Joel Coehoorn,

@Joel Ho aggiunto la versione del metodo di estensione di seguito. Indovina i commenti non supportano il markdown.
Aaron,

13
Nota [^\d]può essere semplificata a\D
pswg

Combinata questa risposta (memorizzazione nella cache del regex nella classe) con il metodo di estensione uno di seguito :)
Vincent Vancalbergh,

73

Puoi farlo facilmente con regex:

string subject = "(913)-444-5555";
string result = Regex.Replace(subject, "[^0-9]", ""); // result = "9134445555"

2
Ha votato per essere un'ottima risposta, ma Joel ti ha battuto. Grazie per la risposta però - mi piace molto vedere la conferma da più fonti.
Matt Dawdy,

@JoSmo Per essere onesti, Joel's può essere convertito in una fodera piuttosto banalmente. (Ma ho anche votato a favore di: D)
Mago Xy

40

Non è necessario utilizzare Regex.

phone = new String(phone.Where(c => char.IsDigit(c)).ToArray())

3
Bella risposta, perché aggiungere ulteriori riferimenti allo spazio dei nomi RegularExpressions
BTE

1
@BTE perché è una scorciatoia che sta semplicemente utilizzandosystem.linq;
Eric Milliot-Martinez il

1
Quanto si comporta bene rispetto alla soluzione Regex?
Shavais,

2
Aggiungendo un test al codice di riferimento di @ Max-PC per la soluzione LINQ si ottiene: StringBuilder: 273ms, Regex: 2096ms, LINQ: 658ms. Più lento di StringBuilder ma ancora significativamente più veloce di Regex. Dato che si tratta di un benchmark di 1.000.000 di sostituzioni, la differenza effettiva tra le soluzioni StringBuilder e LINQ per la maggior parte degli scenari è probabilmente insoddisfacente.
Chris Pratt,

@ChrisPratt per il regex, hai creato un nuovo regex ogni volta o ne hai riutilizzato uno esistente? Ciò potrebbe avere un grande impatto sulle prestazioni.
carlin.scott,

23

Ecco il metodo di estensione per farlo.

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

8

Usando i metodi Regex in .NET dovresti essere in grado di abbinare qualsiasi cifra non numerica usando \ D, in questo modo:

phoneNumber  = Regex.Replace(phoneNumber, "\\D", String.Empty);

5
Questo non è del tutto giusto. È necessario un @ o "\\ D" per sfuggire a \ nella regex. Inoltre, dovresti usare String.Empty invece di ""
Bryan

5

Che ne dici di un metodo di estensione che non usa regex.

Se ti attieni a una delle opzioni Regex, utilizza almeno RegexOptions.Compilednella variabile statica.

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

Questo si basa sulla risposta di Usman Zafar convertita in un gruppo di metodi.


4

per prestazioni ottimali e consumo di memoria inferiore, prova questo:

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, "");
    }
}

Il risultato nel mio computer è:
Init ...
Time: 307
Time: 2178


+1 per mostrare i benchmark. È interessante notare che il ciclo con StringBuilder supera RegEx, anche se immagino abbia senso quando RegEx probabilmente deve superare molte regole per decidere cosa fare.
Steve In CO,

3

Sono sicuro che esiste un modo più efficiente per farlo, ma probabilmente lo farei:

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();
}

Questo è stato il mio primo istinto ed è stato anche il motivo per cui ho chiesto qui. RegEx mi sembra una soluzione molto migliore. Ma grazie per la risposta!
Matt Dawdy,

-1

prova questo

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();
        }

return newPhone.ToString();restituirà "System.Char []". Penso che volevi dire return new string(newPhone);, ma anche questo sta filtrando i numeri 0 e 9 a causa di >e <invece di >=e <=. Ma anche allora la stringa avrà spazi finali perché l' newPhonarray è più lungo del necessario.
juharr
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.