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?

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


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"

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

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

8

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

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

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.


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


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

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

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
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.