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?

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.


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"

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

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

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

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.


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


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

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

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
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.