Ersetzen Sie nicht numerische Zeichen durch leere Zeichenfolgen

125

Schnelle Add-On-Anforderung in unserem Projekt. Ein Feld in unserer Datenbank, in dem eine Telefonnummer gespeichert ist, darf nur 10 Zeichen zulassen. Wenn ich also "(913) -444-5555" oder etwas anderes übergeben bekomme, gibt es eine schnelle Möglichkeit, eine Zeichenfolge durch eine spezielle Ersetzungsfunktion zu führen, bei der ich eine Reihe von Zeichen übergeben kann, um dies zuzulassen?

Regex?

Matt Dawdy
quelle

Antworten:

251

Auf jeden Fall Regex:

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

oder innerhalb einer Klasse, um zu vermeiden, dass der reguläre Ausdruck ständig neu erstellt wird:

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

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

Abhängig von Ihren realen Eingaben möchten Sie möglicherweise eine zusätzliche Logik, um beispielsweise führende 1 (für große Entfernungen) oder alles, was hinter einem x oder X (für Erweiterungen) liegt, zu entfernen.

Joel Coehoorn
quelle
Das ist perfekt. Dies wird nur ein paar Mal verwendet, sodass wir keine Klasse erstellen müssen, und was die führende 1 betrifft, ist dies keine schlechte Idee. Aber ich denke, ich würde das lieber von Fall zu Fall behandeln, zumindest in diesem Projekt. Nochmals vielen Dank - wenn ich noch einmal abstimmen könnte, würde ich.
Matt Dawdy
1
Ich warte darauf, dass jemand eine Erweiterungsmethodenversion für die String-Klasse veröffentlicht :)
Joel Coehoorn
@ Joel Ich habe die unten stehende Version der Erweiterungsmethode hinzugefügt. Vermutlich unterstützen die Kommentare keinen Abschlag.
Aaron
13
Anmerkung [^\d]kann vereinfacht werden, um\D
pswg
Kombinierte diese Antwort (Zwischenspeichern des
regulären Ausdrucks
73

Sie können es einfach mit Regex tun:

string subject = "(913)-444-5555";
string result = Regex.Replace(subject, "[^0-9]", ""); // result = "9134445555"
CMS
quelle
2
Für eine großartige Antwort positiv bewertet, aber Joel hat dich geschlagen. Vielen Dank für die Antwort - ich freue mich sehr über Bestätigungen aus mehreren Quellen.
Matt Dawdy
@JoSmo Um fair zu sein, kann Joel's ziemlich trivial in einen Einzeiler umgewandelt werden. (Aber ich habe auch gestimmt: D)
Magier Xy
40

Sie müssen Regex nicht verwenden.

phone = new String(phone.Where(c => char.IsDigit(c)).ToArray())
Usman Zafar
quelle
3
Schöne Antwort, warum mehr Verweis auf RegularExpressions-Namespace hinzufügen
BTE
1
@ BTE, weil es eine Abkürzung ist, die einfach nutztsystem.linq;
Eric Milliot-Martinez
1
Wie gut funktioniert dies im Vergleich zur Regex-Lösung?
Shavais
2
Das Hinzufügen eines Tests zum Benchmark-Code von @ Max-PC für die LINQ-Lösung führt zu - StringBuilder: 273 ms, Regex: 2096 ms, LINQ: 658 ms. Langsamer als StringBuilder, aber immer noch deutlich schneller als Regex. Angesichts des Benchmarking von 1.000.000 Ersetzungen ist der effektive Unterschied zwischen den StringBuilder- und LINQ-Lösungen für die meisten Szenarien wahrscheinlich vernachlässigbar.
Chris Pratt
@ChrisPratt für den regulären Ausdruck, haben Sie jedes Mal einen neuen regulären Ausdruck erstellt oder einen vorhandenen wiederverwendet? Das könnte einen großen Einfluss auf die Leistung haben.
carlin.scott
23

Hier ist die Methode der Erweiterungsmethode.

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

Mit den Regex-Methoden in .NET sollten Sie in der Lage sein, jede nicht numerische Ziffer mit \ D wie folgt abzugleichen:

phoneNumber  = Regex.Replace(phoneNumber, "\\D", String.Empty);
Wes Mason
quelle
5
Das ist nicht ganz richtig. Sie benötigen ein @ oder "\\ D", um dem \ in der Regex zu entkommen. Außerdem sollten Sie String.Empty anstelle von ""
Bryan
5

Wie wäre es mit einer Erweiterungsmethode, die keinen regulären Ausdruck verwendet?

Wenn Sie sich an eine der Regex-Optionen halten, verwenden Sie diese zumindest RegexOptions.Compiledin der statischen Variablen.

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

Dies baut auf der Antwort von Usman Zafar auf, die in eine Methodengruppe konvertiert wurde.

Michael Lang
quelle
4

Versuchen Sie Folgendes, um die beste Leistung und einen geringeren Speicherverbrauch zu erzielen:

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

Das Ergebnis auf meinem Computer ist:
Init ...
Zeit: 307
Zeit: 2178

Max-PC
quelle
+1 für das Anzeigen von Benchmarks. Interessant, dass die Schleife mit StringBuilder RegEx übertrifft, obwohl es meiner Meinung nach sinnvoll ist, wenn RegEx wahrscheinlich viele Regeln durchlaufen muss, um zu entscheiden, was zu tun ist.
Steve In CO
3

Ich bin mir sicher, dass es einen effizienteren Weg gibt, aber ich würde dies wahrscheinlich tun:

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
quelle
Das war mein erster Instinkt und deshalb habe ich auch hier gefragt. RegEx scheint mir eine viel bessere Lösung zu sein. Aber danke für die Antwort!
Matt Dawdy
-1

Versuche dies

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
quelle
return newPhone.ToString();gibt "System.Char []" zurück. Ich denke du meintest return new string(newPhone);, aber das filtert auch die Zahlen 0 und 9 wegen des >und <anstelle von >=und heraus <=. Aber selbst dann hat der String nachgestellte Leerzeichen, da das newPhonArray länger ist als es sein muss.
Juharr