Sayısal olmayanı boş dizeyle değiştirin


125

Projemizde hızlı ekleme gereksinimi. DB'mizdeki bir telefon numarasını tutacak bir alan yalnızca 10 karaktere izin verecek şekilde ayarlanmıştır. Öyleyse, "(913) -444-5555" veya başka bir şeyden geçersem, bir dizgeyi bir tür özel değiştirme işlevi aracılığıyla çalıştırmanın, ona izin vermek için bir dizi karakter geçirebileceğim hızlı bir yolu var mı?

Regex?

Yanıtlar:


251

Kesinlikle normal ifade:

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

veya bir sınıf içinde normal ifadeyi her zaman yeniden oluşturmaktan kaçınmak için:

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

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

Gerçek dünyadaki girdilerinize bağlı olarak, oradaki 1'leri ayırmak (uzun mesafe için) veya bir x veya X'i takip eden herhangi bir şey (uzantılar için) gibi şeyler yapmak için bazı ek mantık isteyebilirsiniz.


Mükemmel. Bu sadece birkaç kez kullanılır, bu yüzden bir sınıf oluşturmamıza gerek yok ve en başta gelen 1'e gelince, kötü bir fikir değil. Ama sanırım bunu, en azından bu projede, vaka bazında halletmeyi tercih ederim. Tekrar teşekkürler - tekrar oy verebilseydim, yapardım.
Matt Dawdy

1
Birinin string sınıfı için bunun bir uzatma yöntemi versiyonunu göndermesini bekliyorum :)
Joel Coehoorn

@Joel Aşağıya uzatma yöntemi versiyonunu ekledim. Yorumlar, indirimi desteklemiyor sanırım.
Aaron

13
Not [^\d]şu şekilde basitleştirilebilir\D
pswg

Bu yanıtı (sınıfta normal
ifadeyi

73

Bunu normal ifadeyle kolayca yapabilirsiniz:

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

2
Harika bir cevap olduğu için oy kullandı ama Joel seni yendi. Yine de cevabınız için teşekkürler - birden fazla kaynaktan onay görmeyi gerçekten çok seviyorum.
Matt Dawdy

@JoSmo Adil olmak gerekirse, Joel's oldukça önemsiz bir şekilde tek astarlı bir kişiye dönüştürülebilir. (Ama ben de olumlu oy verdim: D)
Mage Xy

40

Regex'i kullanmanıza gerek yok.

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

3
Güzel Cevap, neden RegularExpressions ad alanına daha fazla referans ekleyin
BTE

1
@BTE, çünkü sadece kullanan bir kısa elsystem.linq;
Eric Milliot-Martinez

1
Regex çözümüyle karşılaştırıldığında bu ne kadar iyi performans gösteriyor?
Shavais

2
@ Max-PC'nin LINQ çözümü için karşılaştırma koduna bir test eklemek - StringBuilder: 273ms, Regex: 2096ms, LINQ: 658ms ile sonuçlanır. StringBuilder'dan daha yavaş ama yine de Regex'ten önemli ölçüde daha hızlı. Bunun 1.000.000 değişikliği kıyasladığı düşünüldüğünde, çoğu senaryo için StringBuilder ve LINQ çözümleri arasındaki etkili fark muhtemelen önemsizdir.
Chris Pratt

Düzenli ifade için @ChrisPratt, her seferinde yeni bir normal ifade mi oluşturdunuz yoksa mevcut bir normal ifadeyi mi kullandınız? Bunun performans üzerinde büyük bir etkisi olabilir.
carlin.scott

23

İşte bunu yapmanın uzatma yöntemi.

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

8

.NET'te Regex yöntemlerini kullanarak, \ D kullanarak herhangi bir sayısal olmayan rakamı eşleştirebilmelisiniz, örneğin:

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

5
Bu tam olarak doğru değil. Normal ifadede \ karakterinden çıkmak için @ veya "\\ D" ye ihtiyacınız vardır. Ayrıca, "" yerine String.Empty kullanmalısınız
Bryan

5

Normal ifade kullanmayan bir uzantı yöntemine ne dersiniz?

Normal ifade seçeneklerinden birine bağlı kalırsanız, en azından RegexOptions.Compiledstatik değişkeni kullanın .

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

Bu, Usman Zafar'ın bir yöntem grubuna dönüştürülen cevabına dayanıyor.


4

en iyi performans ve daha düşük bellek tüketimi için şunu deneyin:

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

Bilgisayarımdaki sonuç:
Başlat ...
Saat: 307
Saat: 2178


Karşılaştırmaları göstermek için +1. StringBuilder ile döngünün RegEx'ten daha iyi performans göstermesi ilginçtir, ancak RegEx'in ne yapacağına karar vermek için muhtemelen birçok kuralı gözden geçirmesi gerektiğinde mantıklı geliyor.
Steve In CO

3

Eminim bunu yapmanın daha verimli bir yolu vardır, ama muhtemelen şunu yapardım:

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

Bu benim ilk içgüdümdü ve bu yüzden de burada sordum. RegEx benim için çok daha iyi bir çözüm gibi görünüyor. Ama cevap için teşekkürler!
Matt Dawdy

-1

bunu dene

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();"System.Char []" döndürür. Ne demek düşünüyorum return new string(newPhone);, ama bu aynı zamanda sayılar 0 ve nedeniyle 9 filtreleyerek edilir >ve <yerine >=ve <=. Ancak o zaman bile dizenin sonunda boşluklar olacaktır çünkü newPhondizi olması gerekenden daha uzundur.
juharr
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.