Làm thế nào bạn có thể tách các ký tự không phải ASCII khỏi một chuỗi? (bằng C #)


227

Làm thế nào bạn có thể tách các ký tự không phải ASCII khỏi một chuỗi? (bằng C #)


4
Mỗi câu trả lời của sinelaw bên dưới , nếu bạn muốn thay thế các ký tự không phải ASCII, thay vào đó hãy xem câu trả lời này .
Bobson

Câu trả lời:


414
string s = "søme string";
s = Regex.Replace(s, @"[^\u0000-\u007F]+", string.Empty);

19
Đối với những người trong chúng tôi, RegEx đã thách thức, bạn có phiền khi viết bằng tiếng Anh đơn giản mẫu RegEx của bạn không. Nói cách khác, "the ^ does this", v.v ...
Metro Smurf

47
@Metro Smurf the ^ không phải là nhà điều hành. Nó báo cho regex tìm mọi thứ không khớp, thay vì mọi thứ không khớp. \ U #### - \ u #### cho biết các ký tự nào khớp. \ U0000- \ u007F là tương đương của 255 ký tự đầu tiên trong utf-8 hoặc unicode, luôn là các ký tự ascii. Vì vậy, bạn phù hợp với mọi nhân vật không phải ascii (vì không) và thay thế mọi thứ phù hợp.
Gordon Tucker

41
Phạm vi cho các ký tự có thể in là 0020-007E, dành cho những người tìm kiếm biểu thức thông thường để thay thế các ký tự không in được
Mubashar

1
@GordonTucker \ u0000- \ u007F là tương đương của 127 ký tự đầu tiên trong utf-8 hoặc unicode và KHÔNG phải là 225 đầu tiên. Xem bảng
full_prog_full

4
@full_prog_full Đó là lý do tại sao tôi trả lời chính mình khoảng một phút sau đó tự sửa mình để nói rằng đó là 127 chứ không phải 255. :)
Gordon Tucker

125

Đây là một giải pháp .NET thuần túy không sử dụng các biểu thức thông thường:

string inputString = "Räksmörgås";
string asAscii = Encoding.ASCII.GetString(
    Encoding.Convert(
        Encoding.UTF8,
        Encoding.GetEncoding(
            Encoding.ASCII.EncodingName,
            new EncoderReplacementFallback(string.Empty),
            new DecoderExceptionFallback()
            ),
        Encoding.UTF8.GetBytes(inputString)
    )
);

Nó có thể trông cồng kềnh, nhưng nó phải trực quan. Nó sử dụng mã hóa .NET ASCII để chuyển đổi một chuỗi. UTF8 được sử dụng trong quá trình chuyển đổi vì nó có thể đại diện cho bất kỳ ký tự gốc nào. Nó sử dụng EncoderReplocationFallback để chuyển đổi bất kỳ ký tự không phải ASCII nào thành một chuỗi trống.


5
Hoàn hảo! Tôi đang sử dụng điều này để làm sạch một chuỗi trước khi lưu nó vào tài liệu RTF. Rất nhiều đánh giá cao. Dễ hiểu hơn nhiều so với phiên bản Regex.
Nathan Prather

21
Bạn thực sự thấy nó dễ hiểu hơn? Đối với tôi, tất cả những thứ không thực sự phù hợp (dự phòng, chuyển đổi thành byte, v.v.) đang thu hút sự chú ý khỏi những gì thực sự xảy ra.
bzlm

21
Kiểu như nói tua vít quá khó hiểu nên tôi chỉ dùng búa thay thế.
Brandon

8
@Brandon, thực ra, kỹ thuật này không thực hiện công việc tốt hơn các kỹ thuật khác. Vì vậy, sự tương tự sẽ được sử dụng một tuốc nơ vít cũ đơn giản thay vì một iScrewDriver Deluxe 2000 ưa thích. :)
bzlm

10
Một lợi thế là tôi có thể dễ dàng thay thế ASCII bằng ISO 8859-1 hoặc mã hóa khác :)
Akira Yamamoto

38

Tôi tin rằng MonsCamus có nghĩa là:

parsememo = Regex.Replace(parsememo, @"[^\u0020-\u007E]", string.Empty);

1
IMHO Câu trả lời này tốt hơn câu trả lời được chấp nhận vì nó loại bỏ các ký tự điều khiển.
Dean2690

15

Nếu bạn không muốn tách, nhưng thực sự chuyển đổi tiếng Latin có dấu thành các ký tự không có dấu, hãy xem câu hỏi này: Làm thế nào để tôi dịch các ký tự 8 bit thành các ký tự 7 bit? (tức là Ü đến U)


Tôi thậm chí không nhận ra điều này là có thể, nhưng nó là một giải pháp tốt hơn cho tôi. Tôi sẽ thêm liên kết này vào một nhận xét về câu hỏi để giúp người khác dễ dàng tìm thấy hơn. Cảm ơn!
Bobson

11

Lấy cảm hứng từ giải pháp Biểu thức chính quy của philcruz , tôi đã tạo ra một giải pháp LINQ thuần túy

public static string PureAscii(this string source, char nil = ' ')
{
    var min = '\u0000';
    var max = '\u007F';
    return source.Select(c => c < min ? nil : c > max ? nil : c).ToText();
}

public static string ToText(this IEnumerable<char> source)
{
    var buffer = new StringBuilder();
    foreach (var c in source)
        buffer.Append(c);
    return buffer.ToString();
}

Đây là mã chưa được kiểm tra.


1
Đối với những người không nắm bắt được, đây là giải pháp dựa trên LINQ C # 4.0. :)

7
Thay vì phương thức ToText () riêng biệt, hãy thay thế dòng 3 của PureAscii () bằng: trả về chuỗi mới (source.Select (c => c <min? Nil: c> max? Nil: c) .ToArray ()) ;
đặc vụ

Hoặc có lẽ ToText là: return (chuỗi mới (nguồn)). ToArray () - tùy thuộc vào những gì hoạt động tốt nhất. Thật tuyệt khi có ToText như một phương thức mở rộng - kiểu thông thạo / đường ống. :-)
Bent Rasmussen

Mã đó thay thế các ký tự không phải ASCII bằng một khoảng trắng. Để loại bỏ chúng, thay đổi Chọn thành Ở đâu:return new string( source.Where( c => c >= min && c <= max ).ToArray() );
Foozinator

@Foozinator Mã đó cho phép bạn chỉ định ký tự nào sẽ thay thế các ký tự không phải ASCII bằng. Theo mặc định, nó sử dụng một khoảng trắng, nhưng nếu nó được gọi là .PureASCII (Char.MinValue), thì nó sẽ thay thế tất cả không phải ASCII bằng '\ 0' - vẫn không chính xác tước chúng, nhưng kết quả tương tự.
Ulfius

5

không cần regex. chỉ cần sử dụng mã hóa ...

sOutput = System.Text.Encoding.ASCII.GetString(System.Text.Encoding.ASCII.GetBytes(sInput));

5
Điều này không hoạt động. Điều này không loại bỏ các ký tự unicode, nó thay thế chúng bằng? tính cách.
David

1
@David nói đúng. Ít nhất tôi đã nhận được ????nacho??khi tôi thử: たまねこnachoなちtrong mono 3,4
nacho4d

1
Bạn có thể khởi tạo lớp Mã hóa của riêng mình thay vì thay thế các ký tự, nó sẽ loại bỏ chúng. Xem phương thức GetEncoding: msdn.microsoft.com/en-us/l
Library / 89856k4b (v = vs.110) .aspx

4

Tôi thấy phạm vi thay đổi một chút sau đây hữu ích để phân tích các khối nhận xét ra khỏi cơ sở dữ liệu, điều này có nghĩa là bạn sẽ không phải tranh cãi với tab và thoát các ký tự sẽ khiến trường CSV trở nên khó chịu.

parsememo = Regex.Replace(parsememo, @"[^\u001F-\u007F]", string.Empty);

Nếu bạn muốn tránh các ký tự đặc biệt khác hoặc dấu chấm câu cụ thể, hãy kiểm tra bảng ascii


1
Trong trường hợp bất kỳ ai không chú ý đến các bình luận khác, các ký tự có thể in được thực sự là @ "[^ \ u0020- \ u007E]". Đây là một liên kết để xem bảng nếu bạn tò mò: asciitable.com
scradam

3

Tôi đến đây để tìm giải pháp cho các ký tự ascii mở rộng, nhưng không thể tìm thấy nó. Gần nhất tôi tìm thấy là giải pháp của bzlm . Nhưng điều đó chỉ hoạt động đối với Mã ASCII tối đa 127 (rõ ràng bạn có thể thay thế loại mã hóa trong mã của mình, nhưng tôi nghĩ rằng nó hơi phức tạp để hiểu. Do đó, chia sẻ phiên bản này). Đây là một giải pháp hoạt động cho các mã ASCII mở rộng, tức là lên tới 255 , đó là ISO 8859-1

Nó tìm và loại bỏ các ký tự không phải mã ascii (lớn hơn 255)

Dim str1 as String= "â, ??î or ôu🕧� n☁i✑💴++$-💯♓!🇪🚑🌚‼⁉4⃣od;/⏬'®;😁☕😁:☝)😁😁///😍1!@#"

Dim extendedAscii As Encoding = Encoding.GetEncoding("ISO-8859-1", 
                                                New EncoderReplacementFallback(String.empty),
                                                New DecoderReplacementFallback())

Dim extendedAsciiBytes() As Byte = extendedAscii.GetBytes(str1)

Dim str2 As String = extendedAscii.GetString(extendedAsciiBytes)

console.WriteLine(str2)
'Output : â, ??î or ôu ni++$-!‼⁉4od;/';:)///1!@#$%^yz:

Đây là một bí quyết làm việc cho mã

Thay thế mã hóa theo yêu cầu, phần còn lại sẽ giữ nguyên.


2
Người duy nhất đã làm việc để CHỈ loại bỏ khỏi chuỗi này "Ω c ç ã". Cảm ơn rât nhiều!
Rafael Araújo

2

Đây không phải là hiệu suất tối ưu, nhưng là một cách tiếp cận Linq khá đơn giản:

string strippedString = new string(
    yourString.Where(c => c <= sbyte.MaxValue).ToArray()
    );

Nhược điểm là tất cả các ký tự "sống sót" trước tiên được đưa vào một mảng loại char[]sau đó bị loại bỏ sau khi hàm stringtạo không sử dụng nữa.


1

Tôi đã sử dụng biểu thức regex này:

    string s = "søme string";
    Regex regex = new Regex(@"[^a-zA-Z0-9\s]", (RegexOptions)0);
    return regex.Replace(s, "");

16
Điều này cũng loại bỏ dấu câu, chỉ trong trường hợp đó không phải là điều ai đó muốn.
vẽ Noakes

1

Tôi sử dụng biểu thức chính quy này để lọc các ký tự xấu trong tên tệp.

Regex.Replace(directory, "[^a-zA-Z0-9\\:_\- ]", "")

Đó phải là tất cả các nhân vật được phép cho tên tập tin.


1
Không. Xem Path.GetInvalidPathCharsPath.GetInvalidFileNameChars . Vì vậy, có hàng chục ngàn ký tự hợp lệ.
Tom Blodget

Bạn đúng rồi, Tom. Tôi đã thực sự nghĩ về những cái phổ biến, nhưng tôi đã bỏ qua dấu ngoặc đơn và dấu ngoặc nhọn cũng như tất cả những thứ này - ^% $ # @! & + =.
dùng89032
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.