Jak mogę zamienić niedrukowalne znaki Unicode w Javie?


88

Następujące znaki zastąpią znaki sterujące ASCII (skrót [\x00-\x1F\x7F]):

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

Poniższe zastąpi wszystkie niedrukowalne znaki ASCII (skrót [\p{Graph}\x20]), w tym znaki akcentowane:

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

Jednak żaden z nich nie działa w przypadku ciągów Unicode. Czy ktoś ma dobry sposób na usunięcie niedrukowalnych znaków z ciągu znaków Unicode?


2
Jako dodatek: listę kategorii ogólnych Unicode można znaleźć w UAX # 44
McDowell


1
@Stewart: cześć, czy spojrzałeś na pytanie / odpowiedzi poza tytułem?!?
dagnelies

1
@Stewart: to inne pytanie dotyczy tylko podzbioru znaków ASCII niedrukowalnych !!!
dagnelies

Odpowiedzi:


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

Zobacz więcej o wyrażeniach regularnych Unicode . java.util.regexPattern/ String.replaceAllwspiera ich.


Przynajmniej w Javie 1.6 nie ma dla nich wsparcia. download.oracle.com/javase/6/docs/api/java/util/regex/ ... ... Wypróbowałem też twoją linię, a poza brakiem ukośnika odwrotnego po prostu nie działa.
dagnelies

To działa: char c = 0xFFFA; String.valueOf(c).replaceAll("\\p{C}", "?");również w javadoc do wyszukiwania wzorców w sekcji obsługi Unicode , mówi, że obsługuje kategorie
Op De Cirkel

Masz rację! Przepraszam. Nie zauważyłem tego, ponieważ musiałem dodać kategorie Zl Zp, ponieważ były one głównie źródłem problemów. Działa doskonale. Czy mógłbyś dokonać mini edycji swojego posta, abym mógł ponownie zagłosować?
dagnelies

6
Istnieją również niewidoczne białe znaki (takie jak 0x0200B), które są częścią grupy \ p {Zs}. Niestety, ten zawiera również zwykłe białe znaki. Dla tych, którzy próbują odfiltrować ciąg wejściowy, który nie powinien zawierać żadnych spacji, łańcuch s.replaceAll("[\\p{C}\\p{Z}]", "")spełni urok
Andrey L

1
To jest to, czego szukałem, próbowałem, replaceAll("[^\\u0000-\\uFFFF]", "")ale nie udało mi się
Bibaswann Bandyopadhyay

58

Op De Cirkel ma w większości rację. Jego sugestia zadziała w większości przypadków:

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

Ale jeśli myStringmoże zawierać punkty kodowe inne niż BMP, jest to bardziej skomplikowane. \p{C}zawiera zastępcze punkty kodowe \p{Cs}. Powyższa metoda zamiany spowoduje uszkodzenie punktów kodowych innych niż BMP, czasami zastępując tylko połowę pary zastępczej. Możliwe, że jest to błąd języka Java, a nie zamierzone zachowanie.

Istnieje możliwość skorzystania z innych kategorii składników:

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

Jednak pojedyncze znaki zastępcze niebędące częścią pary (każdy znak zastępczy ma przypisany punkt kodowy) nie zostaną usunięte. Podejście inne niż wyrażenia regularne to jedyny sposób, jaki znam, aby poprawnie obsługiwać \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;
    }
}


4

metody dla Twojego celu

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

Użyłem do tego prostej funkcji:

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

Mam nadzieję, że to jest przydatne.


0

Opierając się na odpowiedziach Op De Cirkel i noackjr , wykonuję następujące czynności w celu ogólnego czyszczenia ciągów: 1. przycinanie wiodących lub końcowych białych znaków, 2. dos2unix, 3. mac2unix, 4. usuwanie wszystkich „niewidocznych znaków Unicode” z wyjątkiem białych znaków:

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

Przetestowano za pomocą Scala REPL.


0

Proponuję usunąć niedrukowalne znaki, jak poniżej, zamiast je zastąpić

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

Przeprojektowałem kod dla numerów telefonów +9 (987) 124124 Wyodrębniłem cyfry z ciągu znaków w Javie

 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 );
}
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.