Ganti non-numerik dengan string kosong

125

Tambah cepat pada persyaratan dalam proyek kami. Bidang di DB kami untuk menyimpan nomor telepon diatur agar hanya memungkinkan 10 karakter. Jadi, jika saya melewati "(913) -444-5555" atau yang lainnya, apakah ada cara cepat untuk menjalankan string melalui semacam fungsi ganti khusus sehingga saya bisa mengopernya serangkaian karakter untuk diizinkan?

Regex?

Matt Dawdy
sumber

Jawaban:

251

Jelas regex:

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

atau di dalam kelas untuk menghindari menciptakan kembali regex sepanjang waktu:

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

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

Bergantung pada input dunia nyata Anda, Anda mungkin ingin beberapa logika tambahan di sana untuk melakukan hal-hal seperti menghapus 1 yang memimpin (untuk jarak jauh) atau apa pun yang mengekstraksi x atau X (untuk ekstensi).

Joel Coehoorn
sumber
Itu sempurna. Ini hanya digunakan beberapa kali, jadi kita tidak perlu membuat kelas, dan sejauh yang 1, bukan ide yang buruk. Tapi saya pikir saya lebih suka menanganinya berdasarkan kasus per kasus, setidaknya dalam proyek ini. Terima kasih lagi - jika saya bisa memperbaiki lagi, saya akan.
Matt Dawdy
1
Saya sedang menunggu seseorang untuk memposting versi metode ekstensi ini untuk kelas string :)
Joel Coehoorn
@ Joel Saya menambahkan versi metode ekstensi di bawah ini. Tebak komentar tidak mendukung penurunan harga.
Aaron
13
Note [^\d]dapat disederhanakan menjadi\D
pswg
Menggabungkan jawaban ini (caching regex di kelas) dengan metode ekstensi satu di bawah ini :)
Vincent Vancalbergh
73

Anda dapat melakukannya dengan mudah dengan regex:

string subject = "(913)-444-5555";
string result = Regex.Replace(subject, "[^0-9]", ""); // result = "9134445555"
CMS
sumber
2
Terpilih karena jawaban yang bagus, tetapi Joel mengalahkan Anda. Terima kasih atas jawabannya - Saya sangat suka melihat konfirmasi dari berbagai sumber.
Matt Dawdy
@ JoSmo Agar adil, Joel's dapat dikonversi menjadi satu-liner cukup sepele. (Tapi saya juga terpilih: D)
Mage Xy
40

Anda tidak perlu menggunakan Regex.

phone = new String(phone.Where(c => char.IsDigit(c)).ToArray())
Usman Zafar
sumber
3
Jawaban Bagus, mengapa menambahkan referensi lebih banyak ke namespace RegularExpressions
BTE
1
@BTE karena ini adalah tulisan tangan pendek yang hanya memanfaatkansystem.linq;
Eric Milliot-Martinez
1
Seberapa baik kinerjanya dibandingkan dengan solusi Regex?
Shavais
2
Menambahkan tes ke kode benchmark @ Max-PC untuk solusi LINQ menghasilkan - StringBuilder: 273ms, Regex: 2096ms, LINQ: 658ms. Lebih lambat dari StringBuilder tetapi masih jauh lebih cepat dari Regex. Mengingat bahwa itu adalah pembandingan penggantian 1.000.000, perbedaan efektif antara solusi StringBuilder dan LINQ untuk sebagian besar skenario mungkin diabaikan.
Chris Pratt
@ ChrisPratt untuk regex, apakah Anda membuat regex baru setiap kali, atau menggunakan kembali yang sudah ada? Itu bisa berdampak besar pada kinerja.
carlin.scott
23

Inilah cara metode ekstensi untuk melakukannya.

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

Menggunakan metode Regex di .NET Anda harus dapat mencocokkan digit non-numerik menggunakan \ D, seperti:

phoneNumber  = Regex.Replace(phoneNumber, "\\D", String.Empty);
Wes Mason
sumber
5
Ini tidak benar. Anda memerlukan @ atau "\\ D" untuk keluar dari \ di regex. Juga, Anda harus menggunakan String.Empty bukannya ""
Bryan
5

Bagaimana dengan metode ekstensi yang tidak menggunakan regex.

Jika Anda tetap menggunakan salah satu opsi Regex setidaknya gunakan RegexOptions.Compileddalam variabel statis.

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

Ini didasarkan pada jawaban Usman Zafar yang dikonversi ke grup metode.

Michael Lang
sumber
4

untuk kinerja terbaik dan konsumsi memori yang lebih rendah, coba ini:

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

Hasilnya di komputer saya adalah:
Init ...
Waktu: 307
Waktu: 2178

Max-PC
sumber
+1 untuk menunjukkan tolok ukur. Menarik bahwa loop dengan StringBuilder mengungguli RegEx, meskipun saya kira masuk akal ketika RegEx mungkin harus mengarungi banyak aturan untuk memutuskan apa yang harus dilakukan.
Steve In CO
3

Saya yakin ada cara yang lebih efisien untuk melakukannya, tetapi saya mungkin akan melakukan ini:

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
sumber
Itu adalah insting pertamaku, dan juga mengapa aku bertanya di sini. RegEx sepertinya solusi yang jauh lebih baik bagi saya. Tapi terima kasih atas jawabannya!
Matt Dawdy
-1

coba ini

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
sumber
return newPhone.ToString();akan mengembalikan "System.Char []". Saya pikir Anda maksud return new string(newPhone);, Tapi ini juga menyaring angka 0 dan 9 karena >dan <bukan >=dan <=. Tetapi bahkan kemudian string akan memiliki spasi tambahan karena newPhonarray lebih panjang dari yang seharusnya.
juharr