Як я можу замінити символи Unicode, що не друкуються, у Java?


88

Наступне замінить символи керування ASCII (скорочення для [\x00-\x1F\x7F]):

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

Далі буде замінено всі недруковані символи ASCII (скорочення для [\p{Graph}\x20]), включаючи символи з наголосом:

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

Однак жоден з них не працює для рядків Unicode. Хтось має хороший спосіб видалити символи, що не друкуються, із рядка Unicode?


2
Як додаток: список загальних категорій Unicode можна знайти в UAX # 44
McDowell


1
@Stewart: привіт, ти дивився на запитання / відповіді крім заголовка?!?
dagnelies

1
@Stewart: це інше питання охоплює лише підмножину ascii недрукованих символів !!!
dagnelies

Відповіді:


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

Докладніше про регулярний вираз Unicode . java.util.regexPattern/ String.replaceAllпідтримує їх.


Принаймні в Java 1.6 для них немає підтримки. download.oracle.com/javase/6/docs/api/java/util/regex/… ... Я також спробував вашу лінію, і крім того, що не було зворотної косої риски, вона просто не працює.
dagnelies

Це працює: char c = 0xFFFA; String.valueOf(c).replaceAll("\\p{C}", "?");також у javadoc для пошуку візерунків у розділі підтримки Unicode , сказано, що він підтримує категорії
Op De Cirkel

Ти правий! Я прошу вибачення. Я цього не помітив, тому що мені довелося додати категорії Zl Zp, оскільки це в основному було джерелом проблем. Це чудово працює. Не могли б ви зробити міні-редагування свого допису, щоб я міг проголосувати за нього ще раз?
dagnelies

6
Є також невидимі пробіли (наприклад, 0x0200B), які є частиною групи \ p {Zs}. На жаль, цей включає також звичайні пробіли. Для тих, хто намагається відфільтрувати вхідний рядок, який не повинен містити пробілів, рядок s.replaceAll("[\\p{C}\\p{Z}]", "")зробить чарівність
Andrey L

1
Це те, що я шукав, намагався, replaceAll("[^\\u0000-\\uFFFF]", "")але не мав успіху
Bibaswann Bandyopadhyay

58

Оп Де Циркель переважно має рацію. Його пропозиція спрацює в більшості випадків:

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

Але якщо вони myStringможуть містити кодові точки, які не є BMP, то це складніше. \p{C}містить сурогатні кодові точки \p{Cs}. Наведений вище метод заміни призведе до пошкодження кодових точок, що не належать до BMP, іноді замінюючи лише половину сурогатної пари. Можливо, це помилка Java, а не передбачувана поведінка.

Варіант використання інших складових категорій:

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

Однак поодинокі сурогатні символи, що не є частиною пари (кожному сурогатному символу присвоєна кодова точка), не видалятимуться. Нерегулярний підхід - це єдиний спосіб, яким я знаю, як правильно обробляти \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

Можливо, вас зацікавлять категорії Unicode "Інше, Керування" та, можливо, "Інше, Формат" (на жаль, останні, здається, містять як символи, що не друкуються, так і для друку).

У регулярних виразах Java ви можете перевірити їх за допомогою \p{Cc}і \p{Cf}відповідно.


Ну, у поганих виразів Java їх немає, але принаймні я зараз отримав список ... краще ніж нічого. спасибі
dagnelies

4

методи в удар для вашої мети

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

Для цього я використав цю просту функцію:

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

Сподіваюся, це корисно.


0

На основі відповідей Op De Cirkel та noackjr , для загального очищення рядків я роблю наступне: 1. обрізання пробілів, що ведуть або закінчуються, 2. dos2unix, 3. mac2unix, 4. видалення всіх "невидимих ​​символів Unicode", крім пробілів:

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

Випробувано Scala REPL.


0

Я пропоную йому видалити символи, що не друкуються, як показано нижче, замість того, щоб замінити їх

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

Я переробив код для телефонних номерів +9 (987) 124124 Витяг цифр із рядка на 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 );
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.