Ответ 1
my_string.replaceAll("\\p{C}", "?");
Подробнее о Unicode regex. java.util.regexPattern
/String.replaceAll
поддерживает их.
Ниже будут заменены управляющие символы ASCII (сокращенное обозначение [\x00-\x1F\x7F]
):
my_string.replaceAll("\\p{Cntrl}", "?");
Ниже будут заменены все непечатаемые символы ASCII (сокращенное обозначение [\p{Graph}\x20]
), включая акцентированные символы:
my_string.replaceAll("[^\\p{Print}]", "?");
Однако ни одно из них не работает для строк Unicode. Кто-нибудь имеет хороший способ удалить непечатаемые символы из строки юникода?
my_string.replaceAll("\\p{C}", "?");
Подробнее о Unicode regex. 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;
}
}
Возможно, вас заинтересуют Unicode-категории "Other, Control" и, возможно, "Other, Format" (к сожалению, последний, похоже, содержит как непечатные, так и печатные символы).
В регулярных выражениях 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;
}
Надеюсь, это полезно.
Основываясь на ответах Op De Cirkel и noackjr, я делаю следующее для общей очистки строк: 1. обрезание начальных или конечных пробелов, 2. dos2unix, 3. mac2unix, 4. удаление всех "невидимых символов Юникода", кроме пробелов:
myString.trim.replaceAll("\r\n", "\n").replaceAll("\r", "\n").replaceAll("[\\p{Cc}\\p{Cf}\\p{Co}\\p{Cn}&&[^\\s]]", "")
Протестировано с Scala REPL.
Я предлагаю убрать непечатаемые символы, как показано ниже, вместо замены
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();
}
Я переработал код для телефонных номеров +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 );
}