Как я могу заменить непечатаемые символы Unicode в Java?


ниже будут заменены управляющие символы ASCII (сокращение для [x00-x1Fx7F]):

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

ниже будут заменены все символы ASCII непечатаемые (стенография для [p{Graph}x20]), в том числе акцентированных символов:

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

однако ни один из них не работает для строк Unicode. У кого-нибудь есть хороший способ удалить непечатаемые символы из строки unicode?

6 61

6 ответов:

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

подробнее о регулярных выражений в Unicode. java.util.regexPattern/String.replaceAll поддерживает их.

Op De Cirkel в основном прав. Его предложение будет работать в большинстве случаев:

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

Вы можете быть заинтересованы в категории Юникода"Другое, Управление" и возможно"Другие", "Формат" (к сожалению, последний, кажется, содержит как непечатные, так и печатные символы).

в регулярных выражениях Java вы можете проверить их с помощью \p{Cc} и \p{Cf} соответственно.

методы в ударе для вашей цели

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]", "");
} 

я использовал эту простую функцию для этого:

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

надеюсь, что это полезно.

я переработал код для номера телефона +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 );
}