Удалить не-UTF-8 символов из xml с объявленной кодировкой = utf-8 - Java
Мне нужно обработать этот сценарий в Java:
Я получаю запрос в форме XML от клиента с объявленной кодировкой = utf-8. К сожалению, он может содержать не символы utf-8, и есть требование удалить эти символы из xml на моей стороне (legacy).
Рассмотрим пример, когда этот недопустимый XML содержит £ (фунт).
1) Я получаю xml как java String с E в нем (у меня нет доступа к интерфейсу прямо сейчас, но я, вероятно, получаю xml как строку java). Могу ли я использовать replaceAll (£, ""), чтобы избавиться от этого персонажа? Любые потенциальные проблемы?
2) Я получаю xml как массив байтов - как безопасно обрабатывать эту операцию в этом случае?
Ответы
Ответ 1
1) Я получаю xml как java String с E в нем (у меня нет доступа к интерфейсу прямо сейчас, но я, вероятно, получаю xml как строку java). Могу ли я использовать replaceAll (£, ""), чтобы избавиться от этого персонажа?
Я предполагаю, что вы скорее подразумеваете, что хотите избавиться от символов < ASCII, потому что вы говорите о "старой" стороне. Вы можете избавиться от чего-либо вне печатаемого диапазона ASCII, используя следующее регулярное выражение:
string = string.replaceAll("[^\\x20-\\x7e]", "");
2) Я получаю xml как массив байтов - как безопасно обрабатывать эту операцию в этом случае?
Вам нужно обернуть byte[]
в ByteArrayInputStream
, чтобы вы могли прочитать их в кодированном символе символа UTF-8 используя InputStreamReader
, в котором вы указываете кодировку, а затем используйте BufferedReader
, чтобы читать его по строкам.
например.
BufferedReader reader = null;
try {
reader = new BufferedReader(new InputStreamReader(new ByteArrayInputStream(bytes), "UTF-8"));
for (String line; (line = reader.readLine()) != null;) {
line = line.replaceAll("[^\\x20-\\x7e]", "");
// ...
}
// ...
Ответ 2
UTF-8 - это кодирование; Unicode - это набор символов. Но символ GBP определенно определен в наборе символов Юникода и, следовательно, наиболее определенно представлен в UTF-8.
Если вы действительно имеете в виду UTF-8, и на самом деле вы пытаетесь удалить последовательности байтов, которые не являются допустимым кодированием символа в UTF-8, тогда...
CharsetDecoder utf8Decoder = Charset.forName("UTF-8").newDecoder();
utf8Decoder.onMalformedInput(CodingErrorAction.IGNORE);
utf8Decoder.onUnmappableCharacter(CodingErrorAction.IGNORE);
ByteBuffer bytes = ...;
CharBuffer parsed = utf8Decoder.decode(bytes);
...
Ответ 3
"test text".replaceAll("[^\\u0000-\\uFFFF]", "");
Этот код удаляет все 4-байтные символы utf8 из строки. Это может понадобиться для некоторых целей при выполнении записи Mysql innodb varchar
Ответ 4
Я столкнулся с такой же проблемой при чтении файлов из локального каталога и попробовал это:
BufferedReader in = new BufferedReader(new InputStreamReader(new FileInputStream(filePath), "UTF-8"));
DocumentBuilder db = DocumentBuilderFactory.newInstance().newDocumentBuilder();
Document xmlDom = db.parse(new InputSource(in));
Возможно, вам придется использовать сетевой входной поток вместо FileInputStream.
-
Капил
Ответ 5
Обратите внимание, что первым шагом должно быть то, что вы спрашиваете создателя XML (который, скорее всего, является источником XML только для генерации XML-данных), чтобы гарантировать правильность их XML перед отправкой вам. Самый простой возможный тест, если они используют Windows, - попросить их просмотреть его в Internet Explorer и увидеть ошибку синтаксического анализа на первом оскорбительном символе.
Пока они исправляют это, вы можете просто написать небольшую программу, которая изменит часть заголовка, чтобы объявить, что кодировка - это ISO-8859-1:
<?xml version="1.0" encoding="iso-8859-1" ?>
а остальные останутся нетронутыми.
Ответ 6
Как только вы преобразуете массив байтов в String на java-машине, вы получите (по умолчанию на большинстве машин) кодированную строку UTF-16. Правильное решение, чтобы избавиться от символов не UTF-8, имеет следующий код:
String[] values = {"\\xF0\\x9F\\x98\\x95", "\\xF0\\x9F\\x91\\x8C", "/*", "look into my eyes 〠.〠", "fkdjsf ksdjfslk", "\\xF0\\x80\\x80\\x80", "aa \\xF0\\x9F\\x98\\x95 aa"};
for (int i = 0; i < values.length; i++) {
System.out.println(values[i].replaceAll(
"[\\\\x00-\\\\x7F]|" + //single-byte sequences 0xxxxxxx
"[\\\\xC0-\\\\xDF][\\\\x80-\\\\xBF]|" + //double-byte sequences 110xxxxx 10xxxxxx
"[\\\\xE0-\\\\xEF][\\\\x80-\\\\xBF]{2}|" + //triple-byte sequences 1110xxxx 10xxxxxx * 2
"[\\\\xF0-\\\\xF7][\\\\x80-\\\\xBF]{3}" //quadruple-byte sequence 11110xxx 10xxxxxx * 3
, ""));
}
или если вы хотите проверить, содержит ли какая-либо строка символы не utf8, вы должны использовать Pattern.matches, например:
String[] values = {"\\xF0\\x9F\\x98\\x95", "\\xF0\\x9F\\x91\\x8C", "/*", "look into my eyes 〠.〠", "fkdjsf ksdjfslk", "\\xF0\\x80\\x80\\x80", "aa \\xF0\\x9F\\x98\\x95 aa"};
for (int i = 0; i < values.length; i++) {
System.out.println(Pattern.matches(
".*(" +
"[\\\\x00-\\\\x7F]|" + //single-byte sequences 0xxxxxxx
"[\\\\xC0-\\\\xDF][\\\\x80-\\\\xBF]|" + //double-byte sequences 110xxxxx 10xxxxxx
"[\\\\xE0-\\\\xEF][\\\\x80-\\\\xBF]{2}|" + //triple-byte sequences 1110xxxx 10xxxxxx * 2
"[\\\\xF0-\\\\xF7][\\\\x80-\\\\xBF]{3}" //quadruple-byte sequence 11110xxx 10xxxxxx * 3
+ ").*"
, values[i]));
}
Если у вас есть массив байтов, который вы могли бы фильтровать еще более правильно:
BufferedReader bufferedReader = null;
try {
bufferedReader = new BufferedReader(new InputStreamReader(new ByteArrayInputStream(bytes), "UTF-8"));
for (String currentLine; (currentLine = bufferedReader.readLine()) != null;) {
currentLine = currentLine.replaceAll(
"[\\x00-\\x7F]|" + //single-byte sequences 0xxxxxxx
"[\\xC0-\\xDF][\\x80-\\xBF]|" + //double-byte sequences 110xxxxx 10xxxxxx
"[\\xE0-\\xEF][\\x80-\\xBF]{2}|" + //triple-byte sequences 1110xxxx 10xxxxxx * 2
"[\\xF0-\\xF7][\\x80-\\xBF]{3}" //quadruple-byte sequence 11110xxx 10xxxxxx * 3
, ""));
}
Для того, чтобы сделать все веб-приложение совместимым с UTF8, читайте здесь:
Как получить UTF-8, работающий в Java Webapps
Подробнее о байтовых кодировках и строках.
Вы можете проверить свой шаблон здесь.
То же самое в PHP здесь.