Làm cách nào để thay thế các ký tự Unicode không in được trong Java?


88

Sau đây sẽ thay thế các ký tự điều khiển ASCII (viết tắt của [\x00-\x1F\x7F]):

my_string.replaceAll("\\p{Cntrl}", "?");

Sau đây sẽ thay thế tất cả các ký tự không in được ASCII (viết tắt của [\p{Graph}\x20]), bao gồm các ký tự có dấu:

my_string.replaceAll("[^\\p{Print}]", "?");

Tuy nhiên, cả hai đều không hoạt động đối với chuỗi Unicode. Có ai có cách hay để loại bỏ các ký tự không in được khỏi chuỗi unicode không?


2
Cũng giống như một phụ lục: danh sách các Danh mục chung Unicode có thể được tìm thấy trong UAX # 44
McDowell


1
@Stewart: chào bạn, bạn đã xem câu hỏi / câu trả lời ngoài tiêu đề chưa?!?
dagnelies

1
@Stewart: câu hỏi khác chỉ bao gồm tập con ascii của các ký tự không in được !!!
dagnelies

Câu trả lời:


134
my_string.replaceAll("\\p{C}", "?");

Xem thêm về Unicode regex . java.util.regexPattern/ String.replaceAllhỗ trợ họ.


Trong java 1.6 ít nhất, không có hỗ trợ cho chúng. download.oracle.com/javase/6/docs/api/java/util/regex/… ... Tôi cũng đã thử dòng của bạn, và ngoài việc thiếu dấu gạch chéo ngược, nó rõ ràng là không hoạt động.
rượu dagnelies

Đây hoạt động: char c = 0xFFFA; String.valueOf(c).replaceAll("\\p{C}", "?");cũng trong javadoc cho mô hình nhìn trong hỗ trợ Unicode phần, nói nó hỗ trợ các loại
Op De Cirkel

Bạn đúng rồi! Tôi xin lỗi. Tôi không nhận thấy điều đó vì tôi phải thêm các danh mục Zl Zp vì chúng hầu hết là nguồn gốc của vấn đề. Nó hoạt động hoàn hảo. Bạn có thể vui lòng thực hiện một chỉnh sửa nhỏ cho bài đăng của mình để tôi có thể bình chọn lại không?
dagnelies

6
Ngoài ra còn có các ký tự khoảng trắng không nhìn thấy (như 0x0200B), là một phần của nhóm \ p {Zs}. Thật không may, cái này cũng bao gồm khoảng trắng bình thường. Đối với những người đang cố gắng để lọc một chuỗi đầu vào mà không được chứa bất kỳ không gian, chuỗi s.replaceAll("[\\p{C}\\p{Z}]", "")sẽ làm sự quyến rũ
Andrey L

1
Đây là những gì tôi đang tìm kiếm, tôi đã cố gắng replaceAll("[^\\u0000-\\uFFFF]", "")nhưng đã không thành công
Bibaswann Bandyopadhyay

58

Op De Cirkel hầu như đúng. Đề xuất của anh ấy sẽ hoạt động trong hầu hết các trường hợp:

myString.replaceAll("\\p{C}", "?");

Nhưng nếu myStringcó thể chứa các điểm mã không phải BMP thì nó phức tạp hơn. \p{C}chứa mã thay thế của \p{Cs}. Phương pháp thay thế ở trên sẽ làm hỏng các điểm mã không phải BMP bằng cách đôi khi chỉ thay thế một nửa cặp thay thế. Có thể đây là một lỗi Java chứ không phải là hành vi dự kiến.

Sử dụng các danh mục cấu thành khác là một tùy chọn:

myString.replaceAll("[\\p{Cc}\\p{Cf}\\p{Co}\\p{Cn}]", "?");

Tuy nhiên, các ký tự đại diện đơn lẻ không thuộc một cặp (mỗi ký tự đại diện có một điểm mã được chỉ định) sẽ không bị xóa. Phương pháp tiếp cận không regex là cách duy nhất tôi biết để xử lý đúng cách \p{C}:

StringBuilder newString = new StringBuilder(myString.length());
for (int offset = 0; offset < myString.length();)
{
    int codePoint = myString.codePointAt(offset);
    offset += Character.charCount(codePoint);

    // Replace invisible control characters and unused code points
    switch (Character.getType(codePoint))
    {
        case Character.CONTROL:     // \p{Cc}
        case Character.FORMAT:      // \p{Cf}
        case Character.PRIVATE_USE: // \p{Co}
        case Character.SURROGATE:   // \p{Cs}
        case Character.UNASSIGNED:  // \p{Cn}
            newString.append('?');
            break;
        default:
            newString.append(Character.toChars(codePoint));
            break;
    }
}

8

Bạn có thể quan tâm đến các danh mục Unicode "Khác, Điều khiển"có thể "Khác, Định dạng" (tiếc là loại sau dường như chứa cả ký tự không in được và có thể in được).

Trong biểu thức chính quy Java, bạn có thể kiểm tra chúng bằng cách sử dụng \p{Cc}\p{Cf}tương ứng.


Chà, các biểu thức java quá tệ không có chúng, nhưng ít nhất tôi đã có danh sách ngay bây giờ ... còn hơn không. cảm ơn
dagnelies

4

các phương pháp đạt được mục tiêu của bạn

public static String removeNonAscii(String str)
{
    return str.replaceAll("[^\\x00-\\x7F]", "");
}

public static String removeNonPrintable(String str) // All Control Char
{
    return str.replaceAll("[\\p{C}]", "");
}

public static String removeSomeControlChar(String str) // Some Control Char
{
    return str.replaceAll("[\\p{Cntrl}\\p{Cc}\\p{Cf}\\p{Co}\\p{Cn}]", "");
}

public static String removeFullControlChar(String str)
{
    return removeNonPrintable(str).replaceAll("[\\r\\n\\t]", "");
} 

0

Tôi đã sử dụng chức năng đơn giản này cho việc này:

private static Pattern pattern = Pattern.compile("[^ -~]");
private static String cleanTheText(String text) {
    Matcher matcher = pattern.matcher(text);
    if ( matcher.find() ) {
        text = text.replace(matcher.group(0), "");
    }
    return text;
}

Hy vọng điều này là hữu ích.


0

Dựa trên câu trả lời của Op De Cirkelnoackjr , sau đây là những gì tôi làm để làm sạch chuỗi chung: 1. cắt bớt khoảng trắng đầu hoặc cuối, 2. dos2unix, 3. mac2unix, 4. xóa tất cả "ký tự Unicode ẩn" ngoại trừ khoảng trắng:

myString.trim.replaceAll("\r\n", "\n").replaceAll("\r", "\n").replaceAll("[\\p{Cc}\\p{Cf}\\p{Co}\\p{Cn}&&[^\\s]]", "")

Đã thử nghiệm với Scala REPL.


0

Tôi đề xuất xóa các ký tự không in được như bên dưới thay vì thay thế nó

private String removeNonBMPCharacters(final String input) {
    StringBuilder strBuilder = new StringBuilder();
    input.codePoints().forEach((i) -> {
        if (Character.isSupplementaryCodePoint(i)) {
            strBuilder.append("?");
        } else {
            strBuilder.append(Character.toChars(i));
        }
    });
    return strBuilder.toString();
}

-4

Tôi đã thiết kế lại mã cho số điện thoại +9 (987) 124124 Trích xuất các chữ số từ một chuỗi trong Java

 public static String stripNonDigitsV2( CharSequence input ) {
    if (input == null)
        return null;
    if ( input.length() == 0 )
        return "";

    char[] result = new char[input.length()];
    int cursor = 0;
    CharBuffer buffer = CharBuffer.wrap( input );
    int i=0;
    while ( i< buffer.length()  ) { //buffer.hasRemaining()
        char chr = buffer.get(i);
        if (chr=='u'){
            i=i+5;
            chr=buffer.get(i);
        }

        if ( chr > 39 && chr < 58 )
            result[cursor++] = chr;
        i=i+1;
    }

    return new String( result, 0, cursor );
}
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.