แทนที่ไม่ใช่ตัวเลขด้วยสตริงว่าง


125

เพิ่มความต้องการอย่างรวดเร็วในโครงการของเรา ฟิลด์ในฐานข้อมูลของเราสำหรับเก็บหมายเลขโทรศัพท์ถูกกำหนดให้อนุญาตเพียง 10 อักขระ ดังนั้นหากฉันผ่าน "(913) -444-5555" หรืออย่างอื่นมีวิธีที่รวดเร็วในการเรียกใช้สตริงผ่านฟังก์ชันการแทนที่พิเศษบางประเภทที่ฉันสามารถส่งชุดอักขระเพื่ออนุญาตได้หรือไม่

regex?

คำตอบ:


251

regex แน่นอน:

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

หรือภายในคลาสเพื่อหลีกเลี่ยงการสร้าง regex ซ้ำตลอดเวลา:

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

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

ขึ้นอยู่กับอินพุตในโลกแห่งความเป็นจริงของคุณคุณอาจต้องการตรรกะเพิ่มเติมที่นั่นเพื่อทำสิ่งต่างๆเช่นตัดเครื่องหมาย 1 นำหน้าออก (สำหรับระยะทางไกล) หรืออะไรก็ตามที่ต่อท้าย x หรือ X (สำหรับส่วนขยาย)


ที่สมบูรณ์แบบ สิ่งนี้ใช้เพียงสองสามครั้งดังนั้นเราจึงไม่จำเป็นต้องสร้างชั้นเรียนและเท่าที่ 1 ชั้นนำไม่ใช่ความคิดที่ไม่ดี แต่ฉันคิดว่าฉันควรจัดการเป็นกรณี ๆ ไปอย่างน้อยก็ในโครงการนี้ ขอบคุณอีกครั้ง - ถ้าฉันสามารถโหวตได้อีกครั้งฉันจะทำ
Matt Dawdy

1
ฉันกำลังรอให้ใครบางคนโพสต์เวอร์ชันวิธีการขยายสำหรับคลาสสตริง :)
Joel Coehoorn

@ Joel ฉันเพิ่มเวอร์ชันวิธีการขยายด้านล่าง เดาว่าความคิดเห็นไม่รองรับ markdown
Aaron

13
หมายเหตุ[^\d]สามารถทำให้ง่ายขึ้นถึง\D
pswg

รวมคำตอบนี้ (แคช regex ในคลาส) กับวิธีการขยายด้านล่าง :)
Vincent Vancalbergh

73

คุณสามารถทำได้อย่างง่ายดายด้วย regex:

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

2
โหวตให้เป็นคำตอบที่ยอดเยี่ยม แต่ Joel เอาชนะคุณได้ ขอบคุณสำหรับคำตอบ - ฉันชอบดูการยืนยันจากหลายแหล่งจริงๆ
Matt Dawdy

@JoSmo เพื่อความยุติธรรม Joel สามารถแปลงเป็นซับเดียวได้ค่อนข้างน่าสนใจ (แต่ฉันก็โหวตแล้วนะ: D)
Mage Xy

40

คุณไม่จำเป็นต้องใช้ Regex

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

3
คำตอบที่ดีทำไมต้องเพิ่มการอ้างอิงไปยังเนมสเปซ RegularExpressions
BTE

1
@BTE เพราะมันเป็นมือสั้นที่ใช้เพียงแค่system.linq;
Eric Milliot-Martinez

1
สิ่งนี้ทำงานได้ดีเพียงใดเมื่อเทียบกับโซลูชัน Regex
Shavais

2
การเพิ่มการทดสอบลงในโค้ดมาตรฐานของ @ Max-PC สำหรับโซลูชัน LINQ จะส่งผลให้ - StringBuilder: 273ms, Regex: 2096ms, LINQ: 658ms ช้ากว่า StringBuilder แต่ยังเร็วกว่า Regex อย่างเห็นได้ชัด เนื่องจากมีการเปรียบเทียบการแทนที่ 1,000,000 ครั้งความแตกต่างที่มีประสิทธิภาพระหว่างโซลูชัน StringBuilder และ LINQ สำหรับสถานการณ์ส่วนใหญ่อาจเป็นไปไม่ได้
Chris Pratt

@ChrisPratt สำหรับ regex คุณสร้าง regex ใหม่ทุกครั้งหรือใช้ regex ที่มีอยู่ใหม่ ซึ่งอาจส่งผลกระทบอย่างมากต่อประสิทธิภาพ
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" เพื่อหลีกเลี่ยง \ ใน regex นอกจากนี้คุณควรใช้ String.Empty แทน ""
Bryan

5

วิธีการขยายที่ไม่ใช้ regex

หากคุณยึดติดกับตัวเลือก Regex อย่างน้อยให้ใช้RegexOptions.Compiledในตัวแปรคงที่

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

สิ่งนี้สร้างจากคำตอบของ Usman Zafar ที่แปลงเป็นกลุ่มวิธีการ


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

ผลลัพธ์ในคอมพิวเตอร์ของฉันคือ: เริ่ม
ต้น ...
เวลา: 307
เวลา: 2178


+1 สำหรับการแสดงเกณฑ์มาตรฐาน น่าสนใจที่การวนซ้ำด้วย StringBuilder มีประสิทธิภาพดีกว่า RegEx แม้ว่าฉันคิดว่ามันสมเหตุสมผลเมื่อ RegEx อาจต้องลุยผ่านกฎมากมายเพื่อตัดสินใจว่าจะทำอย่างไร
Steve In CO

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 ดูเหมือนจะเป็นทางออกที่ดีกว่าสำหรับฉัน แต่ขอบคุณสำหรับคำตอบ!
Matt Dawdy

-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
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.