Bagaimana cara mengganti karakter Unicode yang tidak dapat dicetak di Java?

89

Berikut ini akan menggantikan karakter kontrol ASCII (singkatan dari [\x00-\x1F\x7F]):

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

Berikut ini akan menggantikan semua karakter ASCII yang tidak dapat dicetak (singkatan dari [\p{Graph}\x20]), termasuk karakter beraksen:

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

Namun, tidak ada yang berfungsi untuk string Unicode. Adakah yang punya cara yang baik untuk menghapus karakter yang tidak dapat dicetak dari string unicode?

dagnelies
sumber
2
Hanya sebagai tambahan: daftar Kategori Umum Unicode dapat ditemukan di UAX # 44
McDowell
1
@Stewart: hai, apakah kamu sudah melihat pertanyaan / jawaban selain judul?!?
dagnelies
1
@Stewart: pertanyaan lain itu hanya mencakup subset ascii dari karakter yang tidak dapat dicetak !!!
dagnelies

Jawaban:

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

Lihat lebih lanjut tentang Unicode regex . java.util.regexPatternAku String.replaceAllmendukung mereka.

Op De Cirkel
sumber
Setidaknya di java 1.6, tidak ada dukungan untuk mereka. download.oracle.com/javase/6/docs/api/java/util/regex/… ... Saya juga mencoba baris Anda, dan selain kehilangan garis miring terbalik, itu jelas tidak berfungsi.
dagnelies
Ini berfungsi: char c = 0xFFFA; String.valueOf(c).replaceAll("\\p{C}", "?");juga di javadoc untuk tampilan pola di bagian dukungan Unicode , mengatakan itu mendukung kategori
Op De Cirkel
Kamu benar! Saya minta maaf. Saya tidak menyadarinya karena saya harus menambahkan kategori Zl Zp karena sebagian besar merupakan sumber masalah. Ini bekerja dengan sempurna. Bisakah Anda membuat sedikit pengeditan pada posting Anda sehingga saya dapat memilihnya lagi?
dagnelies
6
Ada juga karakter spasi kosong yang tidak terlihat (seperti 0x0200B), yang merupakan bagian dari grup \ p {Zs}. Sayangnya, yang satu ini juga menyertakan spasi putih normal. Bagi mereka yang mencoba untuk memfilter string input yang tidak boleh mengandung spasi, string s.replaceAll("[\\p{C}\\p{Z}]", "")akan melakukan pesona
Andrey L
1
Inilah yang saya cari, saya mencoba replaceAll("[^\\u0000-\\uFFFF]", "")tetapi tidak berhasil
Bibaswann Bandyopadhyay
58

Op De Cirkel sebagian besar benar. Sarannya akan berhasil dalam banyak kasus:

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

Tetapi jika myStringmungkin berisi titik kode non-BMP maka itu lebih rumit. \p{C}berisi titik kode pengganti \p{Cs}. Metode penggantian di atas akan merusak titik kode non-BMP dengan terkadang hanya mengganti setengah dari pasangan pengganti. Mungkin ini adalah bug Java, bukan perilaku yang dimaksudkan.

Menggunakan kategori konstituen lainnya adalah salah satu pilihan:

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

Namun, karakter pengganti tunggal yang bukan merupakan bagian dari pasangan (setiap karakter pengganti memiliki titik kode yang ditetapkan) tidak akan dihapus. Pendekatan non-regex adalah satu-satunya cara yang saya tahu untuk menangani dengan benar \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;
    }
}
noackjr
sumber
8

Anda mungkin tertarik dengan kategori Unicode "Lainnya, Kontrol" dan mungkin "Lainnya, Format" (sayangnya yang terakhir tampaknya berisi karakter yang tidak dapat dicetak dan dapat dicetak).

Dalam ekspresi reguler Java Anda dapat memeriksanya menggunakan \p{Cc}dan \p{Cf}masing - masing.

Joachim Sauer
sumber
Yah, ekspresi java yang terlalu buruk tidak memilikinya, tapi setidaknya saya mendapatkan daftarnya sekarang ... lebih baik daripada tidak sama sekali. terima kasih
dagnelies
5

metode pukulan untuk tujuan Anda

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]", "");
} 
Ali Bagheri
sumber
0

Saya telah menggunakan fungsi sederhana ini untuk ini:

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;
}

Semoga bermanfaat.

pengguna1300830
sumber
0

Berdasarkan jawaban Op De Cirkel dan noackjr , berikut ini yang saya lakukan untuk pembersihan string umum: 1. memotong spasi putih di depan atau di belakang, 2. dos2unix, 3. mac2unix, 4. menghapus semua "karakter Unicode yang tidak terlihat" kecuali spasi:

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

Diuji dengan Scala REPL.

RyanLeiTaiwan
sumber
0

Saya mengusulkannya menghapus karakter yang tidak dapat dicetak seperti di bawah ini alih-alih menggantinya

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();
}
Ramesh Bathini
sumber
-4

Saya telah mendesain ulang kode untuk nomor telepon +9 (987) 124124 Ekstrak digit dari string di 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 );
}
Kairat Koibagarov
sumber