Как я могу проверить, содержит ли массив байтов строку Unicode в Java?

Мой любимый прием использует , пустой указатель объединяет оператор и круглые скобки, чтобы автоволшебно инстанцировать наборов для меня.

private IList _foo;

public IList ListOfFoo 
    { get { return _foo ?? (_foo = new List()); } }

15
задан james.garriss 3 June 2015 в 19:01
поделиться

5 ответов

Невозможно принять это решение с полной точностью во всех случаях, потому что строка в кодировке UTF-8 является одним из видов произвольных двоичных данных, но вы можете поискать байтовые последовательности, которые недопустимы в UTF-8 . Если вы их найдете, знайте, что это не UTF-8.

Если ваш массив достаточно велик, это должно сработать, поскольку очень вероятно, что такие последовательности появятся в «случайных» двоичных данных, таких как сжатые данные или файлы изображений.

Однако можно получить действительные Данные UTF-8, которые декодируются в совершенно бессмысленную строку символов (возможно, из самых разных скриптов). Это более вероятно для коротких последовательностей. Если тебя это беспокоит, возможно, вам придется провести более тщательный анализ, чтобы увидеть, принадлежат ли все символы, которые являются буквами, к одной и той же кодовой таблице . С другой стороны, это может привести к ложноотрицательным результатам, если у вас есть допустимый ввод текста, который смешивает сценарии.

11
ответ дан 1 December 2019 в 04:10
поделиться

Вопрос предполагает, что существует фундаментальное различие между строковыми и двоичными данными. Хотя это интуитивно так, почти невозможно точно определить, в чем заключается разница.

Строка Java - это последовательность 16-битных величин, соответствующих одной из (почти) 2 ** 16 базовых кодовых точек Unicode. Но если вы посмотрите на эти 16-битные «символы», каждый из них может в равной степени представлять целое число, пару байтов, пиксель и так далее. Битовые шаблоны не имеют ничего внутреннего в том, что говорит то, что они представляют.

Теперь предположим, что вы перефразировали свой вопрос как просьбу о способе отличить ТЕКСТ в кодировке UTF-8 от произвольных двоичных данных. Это помогает? Теоретически нет, потому что битовые шаблоны, которые кодируют любой письменный текст, также могут быть последовательностью чисел. (Трудно сказать что " что произошло с включенными последовательностями встроенного текста?

Таким образом, вы можете сказать, что последовательность байтов определенно не соответствует UTF-8, если декодирование не удалось. Кроме того, если вы сделаете предположения о языке, вы можете сказать, что последовательность байтов , вероятно, или , вероятно, не текстовый документ в кодировке UTF-8.

ИМО, самое лучшее. вы можете сделать это, чтобы не попасть в ситуацию, когда вашей программе необходимо принять это решение. А если этого не удается избежать, знайте, что ваша программа может ошибаться. С мысли и напряженной работы, вы можете сделать это маловероятно, но вероятность никогда не будет равна нулю.

вы можете сказать, что последовательность байтов , вероятно, или , вероятно, не текстовый документ в кодировке UTF-8.

ИМО, лучшее, что вы можете сделать, это избежать попадания в ситуацию где ваша программа должна принять это решение. А если этого не удается избежать, знайте, что ваша программа может ошибаться. С мысли и напряженной работы, вы можете сделать это маловероятно, но вероятность никогда не будет равна нулю.

вы можете сказать, что последовательность байтов , вероятно, или , вероятно, не текстовый документ в кодировке UTF-8.

ИМО, лучшее, что вы можете сделать, это избежать попадания в ситуацию где ваша программа должна принять это решение. А если этого не удается избежать, знайте, что ваша программа может ошибаться. С мысли и напряженной работы, вы можете сделать это маловероятно, но вероятность никогда не будет равна нулю.

3
ответ дан 1 December 2019 в 04:10
поделиться

Вот способ использования "двоичного" регулярного выражения UTF-8 с сайта W3C

static boolean looksLikeUTF8(byte[] utf8) throws UnsupportedEncodingException 
{
  Pattern p = Pattern.compile("\\A(\n" +
    "  [\\x09\\x0A\\x0D\\x20-\\x7E]             # ASCII\\n" +
    "| [\\xC2-\\xDF][\\x80-\\xBF]               # non-overlong 2-byte\n" +
    "|  \\xE0[\\xA0-\\xBF][\\x80-\\xBF]         # excluding overlongs\n" +
    "| [\\xE1-\\xEC\\xEE\\xEF][\\x80-\\xBF]{2}  # straight 3-byte\n" +
    "|  \\xED[\\x80-\\x9F][\\x80-\\xBF]         # excluding surrogates\n" +
    "|  \\xF0[\\x90-\\xBF][\\x80-\\xBF]{2}      # planes 1-3\n" +
    "| [\\xF1-\\xF3][\\x80-\\xBF]{3}            # planes 4-15\n" +
    "|  \\xF4[\\x80-\\x8F][\\x80-\\xBF]{2}      # plane 16\n" +
    ")*\\z", Pattern.COMMENTS);

  String phonyString = new String(utf8, "ISO-8859-1");
  return p.matcher(phonyString).matches();
}

Как было изначально написано, регулярное выражение предназначено для использования в массиве байтов, но вы не можете сделать это с регулярными выражениями Java; цель должна быть чем-то, что реализует интерфейс CharSequence (так что char [] тоже отсутствует). Декодируя байт [] как ISO-8859-1, вы создаете строку, в которой каждый char имеет то же числовое значение без знака, что и соответствующий байт в исходном массиве.

Как отмечали другие, подобные тесты могут только сказать вам, что байт [] может содержать текст UTF-8, а не то, что он содержит . Но регулярное выражение настолько исчерпывающее, что кажется крайне маловероятным, что сырые двоичные данные могут пропустить его. Даже массив всех нулей не t соответствует, поскольку регулярное выражение никогда не соответствует NUL . Если единственные возможности - это UTF-8 и двоичный код, я был бы готов доверять этому тесту.

И пока вы его проводите, вы можете удалить спецификацию UTF-8, если она есть; в противном случае CharsetDecoder UTF-8 передаст его, как если бы это был текст.

UTF-16 был бы намного сложнее, потому что существует очень мало последовательностей байтов, которые всегда недопустимы. Единственные, о ком я могу вспомнить навскидку, - это персонажи с высоким суррогатом, которым не хватает своих товарищей с низким суррогатом, или наоборот. Помимо этого, вам понадобится некоторый контекст, чтобы решить, действительна ли данная последовательность. У вас может быть кириллическая буква, за которой следует китайская идеограмма, за которой следует дингбат со смайликом, но это будет совершенно правильный UTF-16.

Если единственными возможными вариантами являются UTF-8 и двоичный код, я был бы готов доверять этому тесту.

И пока вы его выполняете, вы можете удалить спецификацию UTF-8, если она есть; в противном случае CharsetDecoder UTF-8 передаст его, как если бы это был текст.

UTF-16 был бы намного сложнее, потому что существует очень мало последовательностей байтов, которые всегда недопустимы. Единственные, о ком я могу вспомнить навскидку, - это персонажи с высоким суррогатом, которым не хватает своих товарищей с низким суррогатом, или наоборот. Помимо этого, вам понадобится некоторый контекст, чтобы решить, действительна ли данная последовательность. У вас может быть кириллическая буква, за которой следует китайская идеограмма, за которой следует дингбат со смайликом, но это будет совершенно правильный UTF-16.

Если единственные возможности - это UTF-8 и двоичный код, я был бы готов доверять этому тесту.

И пока вы его проводите, вы можете удалить спецификацию UTF-8, если она есть; в противном случае CharsetDecoder UTF-8 передаст его, как если бы это был текст.

UTF-16 был бы намного сложнее, потому что существует очень мало последовательностей байтов, которые всегда недопустимы. Единственные, о ком я могу вспомнить навскидку, - это персонажи с высоким суррогатом, которым не хватает своих товарищей с низким суррогатом, или наоборот. Помимо этого, вам понадобится некоторый контекст, чтобы решить, действительна ли данная последовательность. У вас может быть кириллическая буква, за которой следует китайская идеограмма, за которой следует дингбат со смайликом, но это будет совершенно правильный UTF-16.

вы можете удалить спецификацию UTF-8, если она есть; в противном случае CharsetDecoder UTF-8 передаст его, как если бы это был текст.

UTF-16 был бы намного сложнее, потому что существует очень мало последовательностей байтов, которые всегда недопустимы. Единственные, о ком я могу вспомнить навскидку, - это персонажи с высоким суррогатом, которым не хватает своих товарищей с низким суррогатом, или наоборот. Помимо этого, вам понадобится некоторый контекст, чтобы решить, действительна ли данная последовательность. У вас может быть кириллическая буква, за которой следует китайская идеограмма, за которой следует дингбат со смайликом, но это будет совершенно правильный UTF-16.

вы можете удалить спецификацию UTF-8, если она есть; в противном случае CharsetDecoder UTF-8 передаст его, как если бы это был текст.

UTF-16 был бы намного сложнее, потому что существует очень мало последовательностей байтов, которые всегда недопустимы. Единственные, о ком я могу вспомнить навскидку, - это персонажи с высоким суррогатом, которым не хватает своих товарищей с низким суррогатом, или наоборот. Помимо этого, вам понадобится некоторый контекст, чтобы решить, действительна ли данная последовательность. У вас может быть кириллическая буква, за которой следует китайская идеограмма, за которой следует дингбат со смайликом, но это будет совершенно правильный UTF-16.

Единственные, о ком я могу вспомнить навскидку, - это персонажи с высоким суррогатом, которым не хватает своих товарищей с низким суррогатом, или наоборот. Помимо этого, вам понадобится некоторый контекст, чтобы решить, действительна ли данная последовательность. У вас может быть кириллическая буква, за которой следует китайская идеограмма, за которой следует дингбат со смайликом, но это будет совершенно правильный UTF-16.

Единственные, о ком я могу вспомнить навскидку, - это персонажи с высоким суррогатом, которым не хватает своих товарищей с низким суррогатом, или наоборот. Помимо этого, вам понадобится некоторый контекст, чтобы решить, действительна ли данная последовательность. У вас может быть кириллическая буква, за которой следует китайская идеограмма, за которой следует дингбат со смайликом, но это будет совершенно правильный UTF-16.

5
ответ дан 1 December 2019 в 04:10
поделиться

Если байтовый массив начинается с метки порядка байтов (BOM), тогда будет легко определить, какая кодировка была использована. Стандартные классы Java для обработки текстовых потоков, вероятно, справятся с этим автоматически.

Если у вас нет спецификации в байтовых данных, это будет значительно труднее - классы .NET могут выполнять статистический анализ, чтобы попытаться решить кодировка,

0
ответ дан 1 December 2019 в 04:10
поделиться

Попробуйте его расшифровать. Если ошибок нет, значит, это допустимая строка UTF-8.

-1
ответ дан 1 December 2019 в 04:10
поделиться
Другие вопросы по тегам:

Похожие вопросы: