Thay thế phi số bằng chuỗi rỗng


125

Thêm nhanh theo yêu cầu trong dự án của chúng tôi. Một trường trong DB của chúng tôi để giữ số điện thoại được đặt thành chỉ cho phép 10 ký tự. Vì vậy, nếu tôi được thông qua "(913) -444-5555" hoặc bất cứ điều gì khác, có cách nào nhanh chóng để chạy một chuỗi thông qua một loại chức năng thay thế đặc biệt mà tôi có thể chuyển cho nó một bộ ký tự để cho phép không?

Regex?

Câu trả lời:


251

Chắc chắn regex:

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

hoặc trong một lớp để tránh tạo lại regex mọi lúc:

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

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

Tùy thuộc vào đầu vào trong thế giới thực của bạn, bạn có thể muốn một số logic bổ sung ở đó để thực hiện những việc như loại bỏ hàng đầu 1 (cho khoảng cách xa) hoặc bất cứ thứ gì theo dấu x hoặc X (cho tiện ích mở rộng).


Thật hoàn hảo. Điều này chỉ được sử dụng một vài lần, vì vậy chúng tôi không cần phải tạo một lớp và cho đến đầu 1, không phải là một ý tưởng tồi. Nhưng tôi nghĩ rằng tôi muốn xử lý nó trong từng trường hợp, ít nhất là trong dự án này. Cảm ơn một lần nữa - nếu tôi có thể upvote một lần nữa, tôi sẽ.
Matt Dawdy

1
Tôi đang chờ ai đó đăng phiên bản phương thức mở rộng này cho lớp chuỗi :)
Joel Coehoorn

@Joel Tôi đã thêm phiên bản phương thức mở rộng bên dưới. Đoán ý kiến ​​không hỗ trợ markdown.
Aaron

13
Lưu ý [^\d]có thể được đơn giản hóa thành\D
pswg

Kết hợp câu trả lời này (lưu bộ đệm regex trong lớp) với phương thức mở rộng dưới đây :)
Vincent Wrapsalbergh

73

Bạn có thể làm điều đó một cách dễ dàng với regex:

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

2
Được khuyến khích vì là một câu trả lời tuyệt vời, nhưng Joel đánh bại bạn. Cảm ơn câu trả lời mặc dù - tôi thực sự muốn xem xác nhận từ nhiều nguồn.
Matt Dawdy

@JoSmo Để công bằng, Joel's có thể được chuyển đổi thành một lớp lót khá tầm thường. (Nhưng tôi cũng đã nâng cấp: D)
Mage Xy

40

Bạn không cần sử dụng Regex.

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

3
Câu trả lời hay, tại sao lại thêm tham chiếu vào không gian tên của CommonExpressions
BTE

1
@BTE bởi vì đó là một tay ngắn chỉ đơn giản là sử dụngsystem.linq;
Eric Milliot-Martinez

1
Điều này thực hiện tốt như thế nào so với giải pháp Regex?
Shavais

2
Thêm một thử nghiệm vào mã điểm chuẩn của @ Max-PC cho giải pháp LINQ dẫn đến - StringBuilder: 273ms, Regex: 2096ms, LINQ: 658ms. Chậm hơn StringBuilder nhưng vẫn nhanh hơn đáng kể so với Regex. Cho rằng đó là điểm chuẩn 1.000.000 thay thế, sự khác biệt hiệu quả giữa các giải pháp StringBuilder và LINQ cho hầu hết các kịch bản có lẽ là không đáng kể.
Chris Pratt

@ChrisPratt cho regex, bạn đã tạo một regex mới mỗi lần hay sử dụng lại một cái hiện có? Điều đó có thể có một tác động lớn đến hiệu suất.
carlin.scott

23

Đây là phương pháp mở rộng để làm điều đó.

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

8

Sử dụng các phương thức Regex trong .NET, bạn sẽ có thể khớp bất kỳ chữ số không phải số nào bằng cách sử dụng \ D, như vậy:

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

5
Điều này không hoàn toàn đúng. Bạn cần một @ hoặc "\\ D" để thoát \ trong regex. Ngoài ra, bạn nên sử dụng String.Empty thay vì ""
Bryan

5

Làm thế nào về một phương pháp mở rộng không sử dụng regex.

Nếu bạn dính vào một trong các tùy chọn Regex ít nhất hãy sử dụng RegexOptions.Compiledtrong biến tĩnh.

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

Điều này được xây dựng dựa trên câu trả lời của Usman Zafar được chuyển đổi thành một nhóm phương thức.


4

để có hiệu suất tốt nhất và mức tiêu thụ bộ nhớ thấp hơn, hãy thử điều này:

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

Kết quả trong máy tính của tôi là: Ban đầu
...
Thời gian: 307
Thời gian: 2178


+1 để hiển thị điểm chuẩn. Điều thú vị là vòng lặp với StringBuilder vượt trội hơn RegEx, mặc dù tôi đoán nó có ý nghĩa khi RegEx có lẽ phải lội qua rất nhiều quy tắc để quyết định phải làm gì.
Steve In CO

3

Tôi chắc chắn có một cách hiệu quả hơn để làm điều đó, nhưng tôi có thể sẽ làm điều này:

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

Đó là bản năng đầu tiên của tôi, và cũng là lý do tại sao tôi hỏi ở đây. RegEx có vẻ như là một giải pháp tốt hơn cho tôi. Nhưng cảm ơn vì câu trả lời!
Matt Dawdy

-1

thử cái này

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();sẽ trả về "System.Char []". Tôi nghĩ bạn có ý đó return new string(newPhone);, nhưng điều này cũng đang lọc ra các số 0 và 9 vì ><thay vì >=<=. Nhưng ngay cả sau đó chuỗi sẽ có khoảng trắng theo sau vì newPhonmảng dài hơn mức cần thiết.
juharr
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.