Замініть нечислові порожніми рядками


125

Швидке додавання до вимог у нашому проекті. Поле в нашій БД для розміщення телефонного номера задано лише 10 символів. Отже, якщо мене пройдуть "(913) -444-5555" чи що-небудь інше, чи є швидкий спосіб запустити рядок через якусь спеціальну функцію заміни, яку я можу передати йому набір символів, щоб дозволити?

Регекс?

Відповіді:


251

Безумовно, регулярний вираз:

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

або в межах класу, щоб уникати повторного створення регулярного вираження:

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

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

Залежно від ваших даних у реальному світі, вам може знадобитися додаткова логіка для того, щоб робити такі речі, як викреслити провідні позиції 1 (на великі відстані) або що-небудь, що відстає від x або X (для розширень).


Це ідеально. Це використовується лише кілька разів, тому нам не потрібно створювати клас, і, наскільки це ведучий 1, не погана ідея. Але я думаю, що я краще вирішуватиму це в кожному конкретному випадку, принаймні в цьому проекті. Ще раз дякую - якби я міг би знову підтримати, я би.
Метт Дауді

1
Я чекаю, коли хтось опублікує версію цього методу для розрядного класу :)
Joel Coehoorn

@Joel Я додав версію способу розширення нижче. Здогадайтесь, коментарі не підтримують розмітку.
Аарон

13
Примітку [^\d]можна спростити до\D
pswg

Поєднав цю відповідь (кешування регексу в класі) із методом розширення один нижче :)
Вінсент Ванкальберг

73

Ви можете легко це зробити за допомогою регулярного вираження:

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

2
Запропонований за те, що він був чудовою відповіддю, але Джоел вибив тебе. Дякую за відповідь - мені дуже подобається бачити підтвердження з багатьох джерел.
Метт Дауді

@JoSmo Щоб бути справедливим, Джоела можна перетворити на однолінійку досить тривіально. (Але я також схвалив: D)
Маг Сі

40

Вам не потрібно використовувати Regex.

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

3
Приємна відповідь, чому додайте більше посилань на простір імен RegularExpressions
BTE

1
@BTE, тому що це просто короткий хід, який просто використовуєтьсяsystem.linq;
Ерік Мілліот-Мартинес

1
Наскільки це ефективно в порівнянні з рішенням Regex?
Шавай

2
Додавання тесту до контрольного коду @ Max-PC для рішення LINQ призводить до - StringBuilder: 273ms, Regex: 2096ms, LINQ: 658ms. Повільніше, ніж StringBuilder, але все ж значно швидше, ніж Regex. Зважаючи на те, що це тестування 1 000 000 замін, ефективна різниця між рішеннями StringBuilder та LINQ для більшості сценаріїв, мабуть, незначна.
Кріс Пратт

@ChrisPratt для регулярного виразу, чи створювали ви кожен раз новий регекс чи повторно використовували існуючий? Це може мати великий вплив на продуктивність.
carlin.scott

23

Ось спосіб способу розширення.

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

8

Використовуючи методи Regex в .NET, ви повинні мати можливість зіставити будь-яку нечислову цифру за допомогою \ D, наприклад:

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

5
Це не зовсім правильно. Щоб уникнути \ в регулярному виразі, вам потрібен @ або "\\ D". Також слід використовувати String.Empty замість ""
Брайан

5

Як щодо методу розширення, який не використовує регулярний вираз.

Якщо ви дотримуєтесь одного з варіантів Regex, принаймні використовуйте RegexOptions.Compiledв статичній змінній.

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

Це ґрунтується на відповіді Усмана Зафара, перетвореної на групу методів.


4

для найкращої продуктивності та зменшення споживання пам’яті спробуйте це:

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

Результат на моєму комп’ютері:
Init ...
Час: 307
Час: 2178


+1 для показу орієнтирів. Цікаво, що цикл із StringBuilder перевершує RegEx, хоча, мабуть, має сенс, коли RegEx, мабуть, повинен пройти безліч правил, щоб вирішити, що робити.
Стів Ін Ко

3

Я впевнений, що є більш ефективний спосіб зробити це, але я, мабуть, зробив би це:

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

Це був мій перший інстинкт, і саме тому я тут запитав. RegEx здається мені набагато кращим рішенням. Але дякую за відповідь!
Метт Дауді

-1

спробуйте це

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 []". Я думаю, ви мали на увазі return new string(newPhone);, але це також фільтрує числа 0 і 9 через >і, <а не >=і <=. Але навіть тоді рядок матиме пробіли, оскільки newPhonмасив довший, ніж потрібно.
juharr
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.