Có cách nào để loại bỏ các dấu và chuyển đổi toàn bộ chuỗi thành các chữ cái thông thường không?


263

Có cách nào tốt hơn để loại bỏ các dấu và làm cho các chữ cái đó thường xuyên ngoài việc sử dụng String.replaceAll()phương thức và thay thế từng chữ cái một không? Thí dụ:

Đầu vào: orčpžsíáýd

Đầu ra: orcpzsiayd

Không cần bao gồm tất cả các chữ cái có dấu như bảng chữ cái tiếng Nga hoặc chữ Trung Quốc.

Câu trả lời:


387

Sử dụng java.text.Normalizerđể xử lý này cho bạn.

string = Normalizer.normalize(string, Normalizer.Form.NFD);
// or Normalizer.Form.NFKD for a more "compatable" deconstruction 

Điều này sẽ tách tất cả các dấu trọng âm từ các nhân vật. Sau đó, bạn chỉ cần so sánh từng nhân vật với việc là một chữ cái và loại bỏ những ký tự không có.

string = string.replaceAll("[^\\p{ASCII}]", "");

Nếu văn bản của bạn ở dạng unicode, bạn nên sử dụng thay thế này:

string = string.replaceAll("\\p{M}", "");

Đối với unicode, \\P{M}khớp với glyph cơ sở và \\p{M}(chữ thường) khớp với từng dấu.

Nhờ GarretWilson cho con trỏ và regular-expressions.info cho hướng dẫn unicode tuyệt vời.


7
Điều này biên dịch biểu thức chính quy mỗi lần, sẽ tốt nếu bạn chỉ cần một lần, nhưng nếu bạn cần làm điều này với nhiều văn bản, biên dịch trước regex là một chiến thắng.
David Conrad

3
Lưu ý rằng không phải tất cả các chữ cái gốc Latinh đều phân rã thành dấu ASCII +. Điều này sẽ giết ví dụ. "Latin {capital, small} letter l with Stro" được sử dụng trong tiếng Ba Lan.
Michał Politowski

12
Đây là một cách tiếp cận tốt, nhưng loại bỏ tất cả các ký tự không phải ASCII là quá mức cần thiết và có thể sẽ xóa những thứ bạn không muốn, như những người khác đã chỉ ra. Sẽ tốt hơn nếu xóa tất cả các "dấu" Unicode; bao gồm các dấu không khoảng cách, dấu cách / kết hợp và dấu kèm theo. Bạn có thể làm điều này với string.replaceAll("\\p{M}", ""). Xem thường xuyên- expressions.info / unicode.html để biết thêm thông tin.
Garret Wilson

4
Bạn có thể muốn sử dụng Normalizer.Form.NFKD thay vì NFD - NFKD sẽ chuyển đổi những thứ như chữ ghép thành ký tự ascii (ví dụ fi thành fi), NFD sẽ không làm điều này.
chesterm8

2
@ chesterm8, thú vị là NFKD đang chuyển đổi "" thành "fi", nhưng nó không chuyển đổi "" thành "AE". Tôi đoán tôi sẽ phải đưa ra dữ liệu Unicode để tìm hiểu lý do tại sao, nhưng đó không phải là điều tôi mong đợi.
Garret Wilson

136

Kể từ năm 2011, bạn có thể sử dụng Apache Commons StringUtils.stripAccents (đầu vào) (kể từ 3.0):

    String input = StringUtils.stripAccents("Tĥïŝ ĩš â fůňķŷ Šťŕĭńġ");
    System.out.println(input);
    // Prints "This is a funky String"

Ghi chú:

Câu trả lời được chấp nhận (Erick Robertson's) không hoạt động cho Ø hoặc. Apache Commons 3.5 không hoạt động cho, nhưng nó hoạt động cho. Sau khi đọc bài viết Wikipedia cho , tôi không chắc nó nên được thay thế bằng "O": đó là một chữ cái riêng trong tiếng Na Uy và tiếng Đan Mạch, được sắp xếp theo thứ tự chữ cái sau "z". Đó là một ví dụ tốt về những hạn chế của phương pháp "điểm nhấn dải".


2
Tôi thấy có một báo cáo lỗi mở cho , @KarolS. Ai đó đã gửi yêu cầu kéo, nhưng nó đã thất bại một số thử nghiệm và chưa được cập nhật kể từ tháng 7 năm ngoái.
DavidS

1
Có bản cập nhật trên đó 5 ngày trước và yêu cầu kéo đã được hợp nhất.
EpicPandaForce

6
Commons Lang 3.5 đã được phát hành vài ngày trước. Tôi xác nhận rằng nó hoạt động trên Ł bây giờ. Nó không hoạt động trên Ø. Đọc bài viết Wiki cho Ø , tôi không chắc chắn nó sẽ được thay thế bằng "O": đó là một lá thư riêng ở Na Uy và Đan Mạch, chữ cái sau "z". Đó là một ví dụ tốt về những hạn chế của phương pháp "điểm nhấn dải".
DavidS

2
Nếu bạn không muốn bao gồm thư viện, bạn có thể dễ dàng sử dụng hai phương thức liên quan đến tính năng đó từ nguồn tại commons.apache.org/proper/commons-lang/apidocs/src-html/org/iêu
lujop

2
Là một người Đan Mạch, tiếng Đan Mạch / tiếng Na Uy cũng giống như tiếng Pháp và tiếng Đức / tiếng Thụy Điển / tiếng Hungary / tiếng Estonia, v.v ... bắt nguồn như một cách viết ngắn. Vì vậy, tùy thuộc vào mục đích của bạn, đây có thể là sự thay thế bạn muốn.
Ole VV

57

Giải pháp của @ virgo47 rất nhanh, nhưng gần đúng. Câu trả lời được chấp nhận sử dụng Trình chuẩn hóa và biểu thức chính quy. Tôi đã tự hỏi phần nào thời gian được sử dụng bởi Trình chuẩn hóa so với biểu thức thông thường, vì việc xóa tất cả các ký tự không phải ASCII có thể được thực hiện mà không cần biểu thức chính quy:

import java.text.Normalizer;

public class Strip {
    public static String flattenToAscii(String string) {
        StringBuilder sb = new StringBuilder(string.length());
        string = Normalizer.normalize(string, Normalizer.Form.NFD);
        for (char c : string.toCharArray()) {
            if (c <= '\u007F') sb.append(c);
        }
        return sb.toString();
    }
}

Tăng tốc độ bổ sung nhỏ có thể đạt được bằng cách viết vào char [] và không gọi tới CharArray (), mặc dù tôi không chắc rằng việc giảm độ rõ của mã có xứng đáng với nó không:

public static String flattenToAscii(String string) {
    char[] out = new char[string.length()];
    string = Normalizer.normalize(string, Normalizer.Form.NFD);
    int j = 0;
    for (int i = 0, n = string.length(); i < n; ++i) {
        char c = string.charAt(i);
        if (c <= '\u007F') out[j++] = c;
    }
    return new String(out);
}

Biến thể này có lợi thế về tính chính xác của cách sử dụng Trình chuẩn hóa và một số tốc độ của bảng sử dụng bảng. Trên máy của tôi, câu hỏi này nhanh hơn khoảng 4 lần so với câu trả lời được chấp nhận và chậm hơn 6,6 lần đến 7 lần so với câu trả lời của @ virgo47 (câu trả lời được chấp nhận chậm hơn khoảng 26 lần so với @ virgo47 trên máy của tôi).


2
outphải được thay đổi kích thước để phù hợp với số lượng ký tự hợp lệ jtrước khi nó được sử dụng để xây dựng đối tượng chuỗi.
Lefteris E

4
Tôi phản đối giải pháp này. Hãy tưởng tượng đầu vào "æøåá". Hiện tại flattenToAsciitạo kết quả "aa .." trong đó các chấm đại diện cho \ u0000. Điều đó không tốt. Câu hỏi đầu tiên là - làm thế nào để thể hiện các ký tự "không bình thường"? Giả sử nó sẽ là?, Hoặc chúng ta có thể để NULL char ở đó, nhưng trong mọi trường hợp chúng ta phải bảo vệ vị trí chính xác của những thứ này (giống như giải pháp regex nào). Đối với điều này, nếu trong vòng lặp phải là một cái gì đó như: if (c <= '\u007F') out[j++] = c; else if (Character.isLetter(c)) out[j++] = '?';Nó sẽ làm chậm nó một chút, nhưng nó phải chính xác ngay từ đầu. ;-)
virgo47

Quảng cáo bình luận cuối cùng của tôi (quá tệ là họ không thể dài hơn) - có thể tích cực ( isLetter) không phải là ý kiến ​​đúng, nhưng tôi không thấy tốt hơn. Tôi không phải là chuyên gia về Unicode, vì vậy tôi không biết cách xác định tốt hơn lớp của ký tự đơn thay thế ký tự gốc. Thư hoạt động tốt cho hầu hết các ứng dụng / tập quán.
virgo47

1
Bạn có thể muốn sử dụng Normalizer.Form.NFKD thay vì NFD - NFKD sẽ chuyển đổi những thứ như chữ ghép thành ký tự ascii (ví dụ fi thành fi), NFD sẽ không làm điều này.
chesterm8

2
Đối với chúng tôi, chúng tôi muốn loại bỏ hoàn toàn nhân vật. Để đảm bảo không có ký tự null nào, tôi đã xóa chúng bằng hàm tạo Chuỗi thay thế: trả về Chuỗi mới (out, 0, j);
Mike Samara

30

EDIT: Nếu bạn không bị mắc kẹt với Java <6 và tốc độ không quan trọng và / hoặc bảng dịch quá giới hạn, hãy sử dụng câu trả lời của David. Vấn đề là sử dụng Normalizer(được giới thiệu trong Java 6) thay vì bảng dịch bên trong vòng lặp.

Mặc dù đây không phải là giải pháp "hoàn hảo", nhưng nó hoạt động tốt khi bạn biết phạm vi (trong trường hợp của chúng tôi là Latin1,2), hoạt động trước Java 6 (không phải là vấn đề thực sự) và nhanh hơn nhiều so với phiên bản được đề xuất nhất (có thể hoặc có thể không phải là một vấn đề):

    /**
 * Mirror of the unicode table from 00c0 to 017f without diacritics.
 */
private static final String tab00c0 = "AAAAAAACEEEEIIII" +
    "DNOOOOO\u00d7\u00d8UUUUYI\u00df" +
    "aaaaaaaceeeeiiii" +
    "\u00f0nooooo\u00f7\u00f8uuuuy\u00fey" +
    "AaAaAaCcCcCcCcDd" +
    "DdEeEeEeEeEeGgGg" +
    "GgGgHhHhIiIiIiIi" +
    "IiJjJjKkkLlLlLlL" +
    "lLlNnNnNnnNnOoOo" +
    "OoOoRrRrRrSsSsSs" +
    "SsTtTtTtUuUuUuUu" +
    "UuUuWwYyYZzZzZzF";

/**
 * Returns string without diacritics - 7 bit approximation.
 *
 * @param source string to convert
 * @return corresponding string without diacritics
 */
public static String removeDiacritic(String source) {
    char[] vysl = new char[source.length()];
    char one;
    for (int i = 0; i < source.length(); i++) {
        one = source.charAt(i);
        if (one >= '\u00c0' && one <= '\u017f') {
            one = tab00c0.charAt((int) one - '\u00c0');
        }
        vysl[i] = one;
    }
    return new String(vysl);
}

Các thử nghiệm trên CTNH của tôi với JDK 32 bit cho thấy điều này thực hiện chuyển đổi từ àèéľšťč89FDČ sang aeelstc89FDC 1 triệu lần trong ~ 100ms trong khi cách Trình chuẩn hóa thực hiện trong 3,7 giây (chậm hơn 37 lần). Trong trường hợp nhu cầu của bạn xoay quanh hiệu suất và bạn biết phạm vi đầu vào, điều này có thể dành cho bạn.

Thưởng thức :-)


1
Rất nhiều sự chậm chạp của phiên bản được đề xuất là do biểu thức thông thường, không phải là Trình chuẩn hóa. Sử dụng Trình chuẩn hóa nhưng loại bỏ các ký tự không phải ASCII 'bằng tay' sẽ nhanh hơn, mặc dù vẫn không nhanh như phiên bản của bạn. Nhưng nó hoạt động cho tất cả Unicode thay vì chỉ latin1 và latin2.
David Conrad

Tôi đã mở rộng phần này để hoạt động với nhiều ký tự hơn, pastebin.com/FAAm6a2j , Lưu ý rằng nó sẽ không hoạt động chính xác với các ký tự đa biến như (DZ). Nó sẽ chỉ tạo ra 1 ký tự từ nó. Ngoài ra chức năng của tôi sử dụng char thay vì chuỗi, nhanh hơn NẾU bạn đang xử lý char anyways, do đó bạn không phải chuyển đổi.
James T

Này, tôi không hiểu những chữ cái trên trường tab00c0 là gì? ví dụ "AAAAAAACEEEEIIII" hoặc "lLlNnNnNnnNnOoOo", v.v. Chưa bao giờ nhìn thấy chúng trước đây. Nơi mà bạn đã tìm thấy chúng? Ngoài ra, tại sao bạn không sử dụng mã lõi?
ThanosFisherman

@ThanosF chỉ cần thử duyệt mã (với trình gỡ lỗi nếu cần). Điều này làm cho mọi ký tự trong một chuỗi: "Đây có phải là ký tự nằm giữa \ u00c0 và \ u017f không? Nếu vậy, hãy thay thế nó bằng ký tự ASCII 7 bit từ bảng." Bảng chỉ bao gồm hai trang mã hóa (Latin 1 và 2) với tương đương 7 bit của chúng. Vì vậy, nếu ký tự có mã \ u00e0 (à), nó sẽ lấy xấp xỉ 7 bit từ vị trí thứ 32 của bảng (e0-c0 = 32) - đó là "a". Một số ký tự không phải là chữ cái, chúng được để lại ở đó với mã của chúng.
virgo47

Cảm ơn lời giải thích của bạn. Tôi có thể tìm các trang mã hóa đó ở đâu để tôi có thể mở rộng Biến này sang ngôn ngữ của mình? (Tiếng Hy Lạp) Câu trả lời được chấp nhận đã thực hiện công việc thay thế các chữ cái có dấu Hy Lạp nhưng tôi cũng muốn thử phương pháp của bạn và chạy một số điểm chuẩn :)
ThanosFisherman

22
System.out.println(Normalizer.normalize("àèé", Normalizer.Form.NFD).replaceAll("\\p{InCombiningDiacriticalMarks}+", ""));

đã làm cho tôi. Đầu ra của đoạn trích trên cho "aee" là thứ tôi muốn, nhưng

System.out.println(Normalizer.normalize("àèé", Normalizer.Form.NFD).replaceAll("[^\\p{ASCII}]", ""));

đã không làm bất kỳ thay thế.


1
Xác nhận điều này ... thông thường ASCII chỉ hoạt động tốt, nhưng tôi đã gặp vấn đề này trên Linux (64b) với JRockit (1.6.0_29 64b). Không thể xác nhận nó với bất kỳ thiết lập nào khác, không thể xác nhận corge đó, nhưng tôi có thể xác nhận rằng giải pháp được đề xuất khác đã hoạt động và tôi đã bỏ phiếu này. :-) (BTW: Nó đã thực hiện một số thay thế, nhưng chưa đủ, nó đã thay đổi Ú thành U chẳng hạn, nhưng không phải là á.)
virgo47

1
Bạn có thể muốn sử dụng Normalizer.Form.NFKD thay vì NFD - NFKD sẽ chuyển đổi những thứ như chữ ghép thành ký tự ascii (ví dụ fi thành fi), NFD sẽ không làm điều này.
chesterm8

@KarolS Tôi không thấy một trong số chúng có chứa bất kỳ dấu
eis

@eis một dấu gạch chéo qua một đếm lá thư như một dấu: en.wikipedia.org/wiki/Diacritic Và nếu bạn đi bằng một định nghĩa chặt chẽ của một "giọng" như trên trang Wikipedia, sau đó dấu tách đôi không phải là một giọng, vì vậy câu trả lời của Nico vẫn sai
Karol S

6

Tùy thuộc vào ngôn ngữ, những từ đó có thể không được coi là dấu (làm thay đổi âm của chữ cái), nhưng dấu phụ

https://en.wikipedia.org/wiki/Diacritic#Lacular_with_letters_contained_diacritics

"Bosnian và Croatia có các ký hiệu č, ć, đ, š và ž, được coi là các chữ cái riêng biệt và được liệt kê như vậy trong từ điển và các bối cảnh khác trong đó các từ được liệt kê theo thứ tự bảng chữ cái."

Loại bỏ chúng có thể là thay đổi ý nghĩa của từ hoặc thay đổi các chữ cái thành những từ hoàn toàn khác nhau.


5
Đã đồng ý. Ví dụ: ở Thụy Điển: "höra" (nghe) -> "hora" (gái điếm)
Christoffer Hammarström

14
Nó không quan trọng ý nghĩa của chúng. Câu hỏi là làm thế nào để loại bỏ chúng.
Erick Robertson

7
Erick: Nó quan trọng những gì họ được gọi. Nếu câu hỏi hỏi làm thế nào để loại bỏ dấu và nếu đó không phải là dấu, thì câu trả lời có thể không chỉ là làm thế nào để loại bỏ tất cả những thứ trông giống như dấu. Mặc dù điều này có lẽ nên là một bình luận và không phải là một câu trả lời.
Smig

4
Tôi nghĩ rằng trường hợp sử dụng thông thường cho việc này là tìm kiếm, đặc biệt là tìm kiếm các ngôn ngữ hỗn hợp, thường sử dụng bàn phím tiếng Anh làm đầu vào, trong trường hợp đó tốt hơn là nhận được dương tính giả hơn là phủ định sai.
nilskp

3

Tôi đã phải đối mặt với cùng một vấn đề liên quan đến kiểm tra tính bằng nhau của Chuỗi, Một trong những chuỗi so sánh có mã ký tự ASCII 128-255 .

tức là không gian không phá vỡ - [Hex - A0] Space [Hex - 20]. Để hiển thị không gian không phá vỡ trên HTML. Tôi đã sử dụng như sau spacing entities. Nhân vật của họ và byte của nó giống như&emsp is very wide space[ ]{-30, -128, -125}, &ensp is somewhat wide space[ ]{-30, -128, -126}, &thinsp is narrow space[ ]{32} , Non HTML Space {}

String s1 = "My Sample Space Data", s2 = "My Sample Space Data";
System.out.format("S1: %s\n", java.util.Arrays.toString(s1.getBytes()));
System.out.format("S2: %s\n", java.util.Arrays.toString(s2.getBytes()));

Đầu ra tính bằng byte:

S1: [77, 121 ,, 3283, 97, 109, 112, 108, 101 ,, 3283, 112, 97, 99, 101 32,, 68, 97, 116, 97] S2: [77, 121 -30, -128, -125,, 83, 97, 109, 112, 108, 101 ,, -30, -128, -12583, 112, 97, 99, 101 -30, -128, -125,, 68, 97, 116, 97]

Sử dụng mã dưới đây cho các không gian khác nhau và mã byte của chúng: wiki for List_of_Unicode_characters

String spacing_entities = "very wide space,narrow space,regular space,invisible separator";
System.out.println("Space String :"+ spacing_entities);
byte[] byteArray = 
    // spacing_entities.getBytes( Charset.forName("UTF-8") );
    // Charset.forName("UTF-8").encode( s2 ).array();
    {-30, -128, -125, 44, -30, -128, -126, 44, 32, 44, -62, -96};
System.out.println("Bytes:"+ Arrays.toString( byteArray ) );
try {
    System.out.format("Bytes to String[%S] \n ", new String(byteArray, "UTF-8"));
} catch (UnsupportedEncodingException e) {
    e.printStackTrace();
}
  • Phiên âm ASCII của chuỗi Unicode cho Java. unidecode

    String initials = Unidecode.decode( s2 );
  • Sử dụng Guava: Google Core Libraries for Java.

    String replaceFrom = CharMatcher.WHITESPACE.replaceFrom( s2, " " );

    Đối với mã hóa URL cho không gian, hãy sử dụng phép lai Guava.

    String encodedString = UrlEscapers.urlFragmentEscaper().escape(inputString);
  • Để khắc phục vấn đề này được sử dụng String.replaceAll()với một số RegularExpression.

    // \p{Z} or \p{Separator}: any kind of whitespace or invisible separator.
    s2 = s2.replaceAll("\\p{Zs}", " ");
    
    
    s2 = s2.replaceAll("[^\\p{ASCII}]", " ");
    s2 = s2.replaceAll(" ", " ");
  • Sử dụng java.text.N normalizer.Form . Enum này cung cấp các hằng số của bốn biểu mẫu chuẩn hóa Unicode được mô tả trong Phụ lục tiêu chuẩn Unicode # 15 - Biểu mẫu chuẩn hóa Unicode và hai phương thức để truy cập chúng.

    nhập mô tả hình ảnh ở đây

    s2 = Normalizer.normalize(s2, Normalizer.Form.NFKC);

Kiểm tra Chuỗi và đầu ra trên các phương pháp khác nhau như ➩ Unidecode, Normalizer, StringUtils .

String strUni = "Tĥïŝ ĩš â fůňķŷ Šťŕĭńġ Æ,Ø,Ð,ß";

// This is a funky String AE,O,D,ss
String initials = Unidecode.decode( strUni );

// Following Produce this o/p: Tĥïŝ ĩš â fůňķŷ Šťŕĭńġ Æ,Ø,Ð,ß
String temp = Normalizer.normalize(strUni, Normalizer.Form.NFD);
Pattern pattern = Pattern.compile("\\p{InCombiningDiacriticalMarks}+");
temp = pattern.matcher(temp).replaceAll("");

String input = org.apache.commons.lang3.StringUtils.stripAccents( strUni );

Sử dụng Unidecodebest choice, Mã cuối cùng của tôi được hiển thị bên dưới.

public static void main(String[] args) {
    String s1 = "My Sample Space Data", s2 = "My Sample Space Data";
    String initials = Unidecode.decode( s2 );
    if( s1.equals(s2)) { //[ , ] %A0 - %2C - %20 « http://www.ascii-code.com/
        System.out.println("Equal Unicode Strings");
    } else if( s1.equals( initials ) ) {
        System.out.println("Equal Non Unicode Strings");
    } else {
        System.out.println("Not Equal");
    }

}

3

Tôi đề nghị Junidecode . Nó sẽ xử lý không chỉ '' và 'Ø', mà còn hoạt động tốt để phiên âm từ các bảng chữ cái khác, chẳng hạn như tiếng Trung Quốc, sang bảng chữ cái Latinh.


1
Có vẻ đầy hứa hẹn, nhưng tôi ước đây là một dự án tích cực / được duy trì hơn và có sẵn trên Maven.
Phil

2

Giải pháp @David Conrad là giải pháp nhanh nhất tôi đã thử sử dụng Trình chuẩn hóa, nhưng nó có một lỗi. Về cơ bản, nó loại bỏ các ký tự không phải là dấu, ví dụ như các ký tự Trung Quốc và các chữ cái khác như, đều bị tước bỏ. Các ký tự mà chúng tôi muốn tách là các dấu không cách nhau, các ký tự không chiếm thêm độ rộng trong chuỗi cuối cùng. Các ký tự có chiều rộng bằng không này về cơ bản kết thúc trong một số ký tự khác. Nếu bạn có thể thấy chúng bị cô lập như một nhân vật, ví dụ như thế này `, tôi đoán là nó được kết hợp với nhân vật không gian.

public static String flattenToAscii(String string) {
    char[] out = new char[string.length()];
    String norm = Normalizer.normalize(string, Normalizer.Form.NFD);

    int j = 0;
    for (int i = 0, n = norm.length(); i < n; ++i) {
        char c = norm.charAt(i);
        int type = Character.getType(c);

        //Log.d(TAG,""+c);
        //by Ricardo, modified the character check for accents, ref: http://stackoverflow.com/a/5697575/689223
        if (type != Character.NON_SPACING_MARK){
            out[j] = c;
            j++;
        }
    }
    //Log.d(TAG,"normalized string:"+norm+"/"+new String(out));
    return new String(out);
}

1

Một trong những cách tốt nhất để sử dụng regex và Trình chuẩn hóa nếu bạn không có thư viện là:

    public String flattenToAscii(String s) {
                if(s == null || s.trim().length() == 0)
                        return "";
                return Normalizer.normalize(s, Normalizer.Form.NFD).replaceAll("[\u0300-\u036F]", "");
}

Điều này hiệu quả hơn thay thế All ("[^ \ p {ASCII}]", "")) và nếu bạn không cần dấu phụ (giống như ví dụ của bạn).

Mặt khác, bạn phải sử dụng mẫu p {ASCII}.

Trân trọng.


0

Tôi nghĩ giải pháp tốt nhất là chuyển đổi từng char thành HEX và thay thế nó bằng một HEX khác. Đó là bởi vì có 2 kiểu gõ Unicode:

Composite Unicode
Precomposed Unicode

Ví dụ: "Xóa" được viết bởi Unicode tổng hợp khác với "Xóa" được viết bởi Unicode được phân tách trước. Bạn có thể sao chép ký tự mẫu của tôi và chuyển đổi chúng để thấy sự khác biệt.

In Composite Unicode, "Ồ" is combined from 2 char: Ô (U+00d4) and ̀ (U+0300)
In Precomposed Unicode, "Ồ" is single char (U+1ED2)

Tôi đã phát triển tính năng này cho một số ngân hàng để chuyển đổi thông tin trước khi gửi nó đến ngân hàng lõi (thường không hỗ trợ Unicode) và gặp phải vấn đề này khi người dùng cuối sử dụng nhiều kiểu gõ Unicode để nhập dữ liệu. Vì vậy, tôi nghĩ rằng, chuyển đổi sang HEX và thay thế nó là cách đáng tin cậy nhất.


-1

Trong trường hợp bất cứ ai đang cố gắng để làm điều này trong kotlin, mã này hoạt động như một lá bùa. Để tránh mâu thuẫn, tôi cũng sử dụng .toUpperCase và Trim (). sau đó tôi bỏ chức năng này:

   fun stripAccents(s: String):String{

   if (s == null) {
      return "";
   }

val chars: CharArray = s.toCharArray()

var sb = StringBuilder(s)
var cont: Int = 0

while (chars.size > cont) {
    var c: kotlin.Char
    c = chars[cont]
    var c2:String = c.toString()
   //these are my needs, in case you need to convert other accents just Add new entries aqui
    c2 = c2.replace("Ã", "A")
    c2 = c2.replace("Õ", "O")
    c2 = c2.replace("Ç", "C")
    c2 = c2.replace("Á", "A")
    c2 = c2.replace("Ó", "O")
    c2 = c2.replace("Ê", "E")
    c2 = c2.replace("É", "E")
    c2 = c2.replace("Ú", "U")

    c = c2.single()
    sb.setCharAt(cont, c)
    cont++

}

return sb.toString()

}

để sử dụng những đoạn mã thú vị như thế này:

     var str: String
     str = editText.text.toString() //get the text from EditText
     str = str.toUpperCase().trim()

     str = stripAccents(str) //call the function
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.