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


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.