У меня есть строка с сбежавшим Unicode символами, \uXXXX
и я хочу , чтобы преобразовать его в обычные буквы Unicode. Например:
"\u0048\u0065\u006C\u006C\u006F World"
должен стать
"Hello World"
Я знаю, что когда я печатаю первую строку, она уже отображается Hello world
. Моя проблема в том, что я читаю имена файлов из файла, а затем ищу их. Имена файлов в файле экранированы кодировкой Unicode, и когда я ищу файлы, я не могу их найти, поскольку он ищет файл с \uXXXX
именем.
\u0048
естьH
- они одно и то же. Строки в Java находятся в Юникоде.a
,b
,$
,£
и т.д.) для целых чисел. Например, символуA
присваивается номер 65, а\n
это 10. Это не имеет ничего общего с тем, как строки или символы представлены на диске или, скажем, в текстовом файле. UTF-8 - это спецификация (т. Е. Кодировка) того, как эти целые числа (т. Е. Символы) представлены как байты (битовые строки), чтобы их можно было однозначно записать и прочитать, скажем, из файла.Ответы:
Технически делаю:
String myString = "\u0048\u0065\u006C\u006C\u006F World";
автоматически преобразует его в
"Hello World"
, поэтому я предполагаю, что вы читаете строку из какого-то файла. Чтобы преобразовать его в «Hello», вам нужно будет разобрать текст на отдельные цифры Unicode (взять\uXXXX
и просто получитьXXXX
), затем сделать,Integer.ParseInt(XXXX, 16)
чтобы получить шестнадцатеричное значение, а затем ввести его,char
чтобы получить фактический символ.Изменить: код для этого:
String str = myString.split(" ")[0]; str = str.replace("\\",""); String[] arr = str.split("u"); String text = ""; for(int i = 1; i < arr.length; i++){ int hexVal = Integer.parseInt(arr[i], 16); text += (char)hexVal; } // Text will now have Hello
источник
Apache Commons Lang StringEscapeUtils.unescapeJava () может декодировать его должным образом.
import org.apache.commons.lang.StringEscapeUtils; @Test public void testUnescapeJava() { String sJava="\\u0048\\u0065\\u006C\\u006C\\u006F"; System.out.println("StringEscapeUtils.unescapeJava(sJava):\n" + StringEscapeUtils.unescapeJava(sJava)); } output: StringEscapeUtils.unescapeJava(sJava): Hello
источник
Вы можете использовать
StringEscapeUtils
с Apache Commons Lang , т.е.String Title = StringEscapeUtils.unescapeJava("\\u0048\\u0065\\u006C\\u006C\\u006F");
источник
Этот простой метод будет работать в большинстве случаев, но может привести к ошибке типа «u005Cu005C», который должен декодировать строку «\ u0048», но на самом деле будет декодировать «H», поскольку первый проход создает «\ u0048» как рабочую строку, которая затем снова обрабатывается циклом while.
static final String decode(final String in) { String working = in; int index; index = working.indexOf("\\u"); while(index > -1) { int length = working.length(); if(index > (length-6))break; int numStart = index + 2; int numFinish = numStart + 4; String substring = working.substring(numStart, numFinish); int number = Integer.parseInt(substring,16); String stringStart = working.substring(0, index); String stringEnd = working.substring(numFinish); working = stringStart + ((char)number) + stringEnd; index = working.indexOf("\\u"); } return working; }
источник
Укороченная версия:
public static String unescapeJava(String escaped) { if(escaped.indexOf("\\u")==-1) return escaped; String processed=""; int position=escaped.indexOf("\\u"); while(position!=-1) { if(position!=0) processed+=escaped.substring(0,position); String token=escaped.substring(position+2,position+6); escaped=escaped.substring(position+6); processed+=(char)Integer.parseInt(token,16); position=escaped.indexOf("\\u"); } processed+=escaped; return processed; }
источник
StringEscapeUtils из библиотеки org.apache.commons.lang3 устарел с версии 3.6.
Таким образом, вы можете вместо этого использовать их новую библиотеку обычного текста :
compile 'org.apache.commons:commons-text:1.9' OR <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-text</artifactId> <version>1.9</version> </dependency>
Пример кода:
источник
Это не совсем ясно из вашего вопроса, но я предполагаю, что вы говорите, что у вас есть файл, в котором каждая строка этого файла является именем файла. И каждое имя файла выглядит примерно так:
Другими словами, символы в файле имен файлов
\
,u
,0
,0
,4
,8
и так далее.Если да, то то, что вы видите, ожидаемо. Java переводит
\uXXXX
последовательности только в строковых литералах в исходном коде (и при чтении сохраненныхProperties
объектов). Когда вы читаете содержимое, файл , который вы будете иметь строку , состоящую из символов\
,u
,0
,0
,4
,8
и так далее и не строкаHello
.Таким образом, вам нужно будет проанализировать эту строку, чтобы извлечь части
0048
,0065
и т. Д., А затем преобразовать их вchar
s и создать строку из этихchar
s, а затем передать эту строку в процедуру, которая открывает файл.источник
Обновления относительно ответов, предлагающих использовать Apache Commons Lang's: StringEscapeUtils.unescapeJava () - он устарел,
Замена Apache Commons Text «сек StringEscapeUtils.unescapeJava ()
источник
Просто хотел внести свою версию, используя регулярное выражение:
private static final String UNICODE_REGEX = "\\\\u([0-9a-f]{4})"; private static final Pattern UNICODE_PATTERN = Pattern.compile(UNICODE_REGEX); ... String message = "\u0048\u0065\u006C\u006C\u006F World"; Matcher matcher = UNICODE_PATTERN.matcher(message); StringBuffer decodedMessage = new StringBuffer(); while (matcher.find()) { matcher.appendReplacement( decodedMessage, String.valueOf((char) Integer.parseInt(matcher.group(1), 16))); } matcher.appendTail(decodedMessage); System.out.println(decodedMessage.toString());
источник
Я написал эффективное и защищенное от ошибок решение:
public static final String decode(final String in) { int p1 = in.indexOf("\\u"); if (p1 < 0) return in; StringBuilder sb = new StringBuilder(); while (true) { int p2 = p1 + 6; if (p2 > in.length()) { sb.append(in.subSequence(p1, in.length())); break; } try { int c = Integer.parseInt(in.substring(p1 + 2, p1 + 6), 16); sb.append((char) c); p1 += 6; } catch (Exception e) { sb.append(in.subSequence(p1, p1 + 2)); p1 += 2; } int p0 = in.indexOf("\\u", p1); if (p0 < 0) { sb.append(in.subSequence(p1, in.length())); break; } else { sb.append(in.subSequence(p1, p0)); p1 = p0; } } return sb.toString(); }
источник
пытаться
private static final Charset UTF_8 = Charset.forName("UTF-8"); private String forceUtf8Coding(String input) {return new String(input.getBytes(UTF_8), UTF_8))}
источник
один простой способ, который я знаю, используя JsonObject:
try { JSONObject json = new JSONObject(); json.put("string", myString); String converted = json.getString("string"); } catch (JSONException e) { e.printStackTrace(); }
источник
Вот мое решение ...
String decodedName = JwtJson.substring(startOfName, endOfName); StringBuilder builtName = new StringBuilder(); int i = 0; while ( i < decodedName.length() ) { if ( decodedName.substring(i).startsWith("\\u")) { i=i+2; builtName.append(Character.toChars(Integer.parseInt(decodedName.substring(i,i+4), 16))); i=i+4; } else { builtName.append(decodedName.charAt(i)); i = i+1; } };
источник
Быстрый
fun unicodeDecode(unicode: String): String { val stringBuffer = StringBuilder() var i = 0 while (i < unicode.length) { if (i + 1 < unicode.length) if (unicode[i].toString() + unicode[i + 1].toString() == "\\u") { val symbol = unicode.substring(i + 2, i + 6) val c = Integer.parseInt(symbol, 16) stringBuffer.append(c.toChar()) i += 5 } else stringBuffer.append(unicode[i]) i++ } return stringBuffer.toString() }
источник
Собственно, я написал библиотеку с открытым исходным кодом, которая содержит некоторые утилиты. Один из них - преобразование последовательности Unicode в String и наоборот. Я нахожу это очень полезным. Вот цитата из статьи об этой библиотеке о конвертере Unicode:
Вот ссылка на всю статью, в которой объясняется, какие утилиты есть в библиотеке и как заставить библиотеку их использовать. Он доступен как артефакт Maven или как исходный код на Github. Он очень прост в использовании. Библиотека Java с открытым исходным кодом с фильтрацией трассировки стека, конвертером Unicode для синтаксического анализа строк и сравнением версий
источник
Для Java 9+ вы можете использовать новый метод replaceAll класса Matcher .
private static final Pattern UNICODE_PATTERN = Pattern.compile("\\\\u([0-9A-Fa-f]{4})"); public static String unescapeUnicode(String unescaped) { return UNICODE_PATTERN.matcher(unescaped).replaceAll(r -> String.valueOf((char) Integer.parseInt(r.group(1), 16))); } public static void main(String[] args) { String originalMessage = "\\u0048\\u0065\\u006C\\u006C\\u006F World"; String unescapedMessage = unescapeUnicode(originalMessage); System.out.println(unescapedMessage); }
Я считаю , что главное преимущество этого подхода над unescapeJava по StringEscapeUtils (кроме того , не используя дополнительную библиотеку) является то , что вы можете конвертировать только символы Unicode (если вы хотите), поскольку последняя преобразует все сбежавших Java символы (например , \ п или \ т ). Если вы предпочитаете преобразовывать все экранированные символы, библиотека действительно лучший вариант.
источник
@NominSim Может быть другой символ, поэтому я должен определить его по длине.
private String forceUtf8Coding(String str) { str = str.replace("\\",""); String[] arr = str.split("u"); StringBuilder text = new StringBuilder(); for(int i = 1; i < arr.length; i++){ String a = arr[i]; String b = ""; if (arr[i].length() > 4){ a = arr[i].substring(0, 4); b = arr[i].substring(4); } int hexVal = Integer.parseInt(a, 16); text.append((char) hexVal).append(b); } return text.toString(); }
источник
UnicodeUnescaper
изorg.apache.commons:commons-text
тоже приемлемо.new UnicodeUnescaper().translate("\u0048\u0065\u006C\u006C\u006F World")
возвращается"Hello World"
источник
Альтернативный способ достижения этого может заключаться в использовании
chars()
введенного в Java 9, его можно использовать для итерации по символам, гарантируя, что любой char, который сопоставляется с суррогатной кодовой точкой , передается неинтерпретированным. Это можно использовать как: -String myString = "\u0048\u0065\u006C\u006C\u006F World"; myString.chars().forEach(a -> System.out.print((char)a)); // would print "Hello World"
источник
Я обнаружил, что многие ответы не касались вопроса «дополнительных символов». Вот правильный способ поддержать это. Никаких сторонних библиотек, чистая реализация Java.
http://www.oracle.com/us/technologies/java/supplementary-142654.html
public static String fromUnicode(String unicode) { String str = unicode.replace("\\", ""); String[] arr = str.split("u"); StringBuffer text = new StringBuffer(); for (int i = 1; i < arr.length; i++) { int hexVal = Integer.parseInt(arr[i], 16); text.append(Character.toChars(hexVal)); } return text.toString(); } public static String toUnicode(String text) { StringBuffer sb = new StringBuffer(); for (int i = 0; i < text.length(); i++) { int codePoint = text.codePointAt(i); // Skip over the second char in a surrogate pair if (codePoint > 0xffff) { i++; } String hex = Integer.toHexString(codePoint); sb.append("\\u"); for (int j = 0; j < 4 - hex.length(); j++) { sb.append("0"); } sb.append(hex); } return sb.toString(); } @Test public void toUnicode() { System.out.println(toUnicode("😊")); System.out.println(toUnicode("🥰")); System.out.println(toUnicode("Hello World")); } // output: // \u1f60a // \u1f970 // \u0048\u0065\u006c\u006c\u006f\u0020\u0057\u006f\u0072\u006c\u0064 @Test public void fromUnicode() { System.out.println(fromUnicode("\\u1f60a")); System.out.println(fromUnicode("\\u1f970")); System.out.println(fromUnicode("\\u0048\\u0065\\u006c\\u006c\\u006f\\u0020\\u0057\\u006f\\u0072\\u006c\\u0064")); } // output: // 😊 // 🥰 // Hello World
источник
Решение для Котлина:
val sourceContent = File("test.txt").readText(Charset.forName("windows-1251")) val result = String(sourceContent.toByteArray())
Kotlin везде использует UTF-8 в качестве кодировки по умолчанию.
У метода
toByteArray()
есть аргумент по умолчанию -Charsets.UTF_8
.источник
String(string.toByteArray())
буквально ничего не добивается.toByteArray()
имеет аргумент по умолчанию сCharsets.UTF_8
. Затем вы создаете строку из массива байтов с требуемой кодировкой. Я тестировал сегодня сwindows-1251
UTF-8, он работает. Также я сделал сравнение на байтовом уровне :)