Не могу преобразовать символы Юникода в кириллицу

У меня в Apache Lucene сохранилась куча документов с некоторыми именами на русском языке, и когда я пытаюсь их распечатать, это выглядит как "\u0410\u0441\u043f\u0430\u0440", но не в кириллице. Проект находится на Scala. Я пытался исправить это с помощью метода Apache Commons unescapeJava, но это не помогло. Есть ли другие варианты?

Обновлено: проект написан с использованием фреймворка Spray и возвращает json следующим образом.

{
  "id" : 0,
  "name" : "\u0410\u0441\u043f\u0430\u0440"
}

person 4lex1v    schedule 13.02.2013    source источник
comment
Аспар, это ожидаемый результат? Потому что для меня это работает. Убедитесь, что вы закодировали его в UTF-16   -  person Danyel    schedule 13.02.2013
comment
@Даниэль Да, в общем, но это просто пример   -  person 4lex1v    schedule 13.02.2013
comment
Неясно, является ли это фактическим содержимым строки или просто результатом некоторого экранирования, выполненного при ее печати. Можете ли вы сказать нам, что печатает println(theString.length)? Если это 5, то проблема не в строке, а в том, как она отображается.   -  person Régis Jean-Gilles    schedule 13.02.2013
comment
@RégisJean-Gilles Да, если я напишу result.mkString, он вернет его кириллическими символами, но мне нужно это как json   -  person 4lex1v    schedule 13.02.2013


Ответы (2)


Я попытаюсь сделать вывод, что именно вы делаете. Вы используете спрей, поэтому я понимаю, что вы используете его библиотеку json "spray-json"

Итак, я предполагаю, что у вас есть некоторый экземпляр spray.json.JsObject, и то, что вы разместили в своем вопросе, - это то, что вы получаете в качестве вывода при печати этого экземпляра. Ваш объект json верен, значение поля name не имеет встроенного экранирования, на самом деле это преобразование в строку, которая экранирует некоторые символы Юникода.

См. определение printString здесь: https://github.com/spray/spray-json/blob/master/src/main/scala/spray/json/JsonPrinter.scala

Я также предполагаю, что когда вы пытались использовать unescapeJava, вы применили его к значению поля name, создав новый экземпляр spray.json.JsObject, который вы затем распечатали, как и раньше. Учитывая, что ваш объект json на самом деле не имеет экранирования, это абсолютно ничего не дало, а затем при печати принтер выполняет экранирование, как и раньше, и вы возвращаетесь к исходной точке.

В качестве примечания стоит упомянуть, что спецификация json не указывает, как кодируются символы: они могут храниться либо как их буквальное значение, либо как escape-последовательность Unicode. Например, строка "abc" может быть описана просто как "abc" или как "\u0061\u0062\u0063". Любая форма является правильной. Просто так получилось, что автор spray-json решил использовать последнюю форму для всех символов, отличных от ascii.

Итак, теперь вы спрашиваете, что я могу сделать, чтобы обойти это? Вы можете попросить автора spray-json добавить параметр, который позволит вам указать, что вы не хотите экранирования юникода. Но я полагаю, что вам нужно решение прямо сейчас.

Самое простое — просто преобразовать объект в строку (через JsValue.toString, JsValue.compactPrint или JsValue.prettyPrint) и затем передать результат в unescapeJava. По крайней мере, это вернет вам ваши кириллические оригинальные символы. Но это немного грубо и на самом деле довольно опасно, поскольку некоторые символы небезопасно экранировать внутри строкового литерала. Например: \n будет преобразовано в фактический возврат, а \u0022 будет преобразовано в ". Вы можете легко увидеть, как это сломает ваш документ json. Но, по крайней мере, это позволит подтвердить мою теорию (помните, что я делал предположения о том, что именно вы делаете).

Теперь для правильного исправления: вы можете просто расширить JsonPrinter и переопределить его метод printString, чтобы удалить экранирование юникода. Что-то вроде этого (не проверено):

trait NoUnicodeEscJsonPrinter extends JsonPrinter {
  override protected def printString(s: String, sb: StringBuilder) {
    @tailrec
    def printEscaped(s: String, ix: Int) {
      if (ix < s.length) {
        s.charAt(ix) match {
          case '"' => sb.append("\\\"")
          case '\\' => sb.append("\\\\")
          case x if 0x20 <= x && x < 0x7F => sb.append(x)
          case '\b' => sb.append("\\b")
          case '\f' => sb.append("\\f")
          case '\n' => sb.append("\\n")
          case '\r' => sb.append("\\r")
          case '\t' => sb.append("\\t")
          case x => sb.append(x)
        }
        printEscaped(s, ix + 1)
      }
    }
    sb.append('"')
    printEscaped(s, 0)
    sb.append('"')
  }
}

trait NoUnicodeEscPrettyPrinter  extends PrettyPrinter with NoUnicodeEscJsonPrinter
object NoUnicodeEscPrettyPrinter extends NoUnicodeEscPrettyPrinter

trait NoUnicodeEscCompactPrinter   extends CompactPrinter  with NoUnicodeEscJsonPrinter
object NoUnicodeEscCompactPrinter  extends NoUnicodeEscCompactPrinter

Затем вы можете сделать:

val json: JsValue = ...
val jsonString: String = NoUnicodeEscPrettyPrinter( json )

jsonString будет содержать ваш документ json в формате симпатичной печати и без экранирования юникода.

person Régis Jean-Gilles    schedule 13.02.2013
comment
+1 за очень хороший ответ и выдающиеся телепатические способности :) - person 4e6; 13.02.2013
comment
Спасибо за ответ =) Вы были правы, но мы решили конвертировать их на стороне браузера - person 4lex1v; 15.02.2013

Эта проблема исправлена ​​в spray-json 1.3.2: https://github.com/spray/spray-json/issues/46

Я столкнулся с аналогичной проблемой с арабскими символами, используя Akka HTTP 1.0, который зависит от 1.3.1. При обновлении до 1.3.2 моя проблема была решена.

person Jason Bass    schedule 03.11.2015