Как насчет этого:
String input = ... // my UTF-16 string
StringBuilder sb = new StringBuilder(input.length());
for (int i = 0; i < input.length(); i++) {
char ch = input.charAt(i);
if (ch <= 0xFF) {
sb.append(ch);
}
}
byte[] ascii = sb.toString().getBytes("ISO-8859-1"); // aka LATIN-1
Вероятно, это не самый эффективный способ преобразования больших строк, поскольку мы копируем символы дважды. Тем не менее, у него есть преимущество в том, что он прямолинеен.
Кстати, строго говоря, нет такого набора символов, как 8-битный ASCII. ASCII — это 7-битный набор символов. LATIN-1 ближе всего к «8-битному набору символов ASCII» (и блок 0 Unicode эквивалентен LATIN-1), поэтому я предполагаю, что вы имеете в виду именно это.
РЕДАКТИРОВАТЬ: в свете обновления вопроса решение еще проще:
String input = ... // my UTF-16 string
byte[] ascii = new byte[input.length()];
for (int i = 0; i < input.length(); i++) {
ascii[i] = (byte) input.charAt(i);
}
Это решение является более эффективным. Поскольку теперь мы знаем, сколько байтов ожидать, мы можем предварительно выделить массив байтов и скопировать (усеченные) символы без использования StringBuilder в качестве промежуточного буфера.
Однако я не уверен, что такое обращение с неверными данными разумно.
РЕДАКТИРОВАТЬ 2: с этим есть еще одна неясная ошибка. Unicode фактически определяет кодовые точки (символы) как «примерно 21-битные» значения ... от 0x000000 до 0x10FFFF ... и использует суррогаты для представления кодов> 0x00FFFF. Другими словами, кодовая точка Unicode> 0x00FFFF фактически представлена в UTF-16 как два «символа». Ни мой ответ, ни какой-либо другой не учитывают этот (по общему признанию эзотерический) момент. На самом деле, работать с кодовыми точками > 0x00FFFF в Java довольно сложно. Это связано с тем, что 'char' является 16-битным типом, а String определяется в терминах 'char'.
РЕДАКТИРОВАТЬ 3: возможно, более разумным решением для работы с неожиданными символами, которые не преобразуются в ASCII, является замена их стандартным символом замены:
String input = ... // my UTF-16 string
byte[] ascii = new byte[input.length()];
for (int i = 0; i < input.length(); i++) {
char ch = input.charAt(i);
ascii[i] = (ch <= 0xFF) ? (byte) ch : (byte) '?';
}
person
Stephen C
schedule
29.09.2009