У меня есть строка, которая выглядит так:
{\x22documentReferer\x22:\x22http:\x5C/\x5C/pikabu.ru\x5C/freshitems.php\x22}
Как я мог преобразовать это в читаемый JSON?
Я нашел различные медленные решения, подобные здесь с regEx
Уже пробовали:
URL.decode
StringEscapeUtils
JSON.parse // from different libraries
Например, python имеет простое решение, такое как декодирование из 'string_escape'
Связанный возможный дубликат относится к Python, и мой вопрос касается Java или Scala
Рабочее, но также очень медленное решение, которое я использую сейчас, происходит отсюда:
def unescape(oldstr: String): String = {
val newstr = new StringBuilder(oldstr.length)
var saw_backslash = false
var i = 0
while (i < oldstr.length) {
{
val cp = oldstr.codePointAt(i)
if (!saw_backslash) {
if (cp == '\\') saw_backslash = true
else newstr.append(cp.toChar)
} else {
if (cp == '\\') {
saw_backslash = false
newstr.append('\\')
newstr.append('\\')
} else {
if (cp == 'x') {
if (i + 2 > oldstr.length) die("string too short for \\x escape")
i += 1
var value = 0
try
value = Integer.parseInt(oldstr.substring(i, i + 2), 16)
catch {
case nfe: NumberFormatException =>
die("invalid hex value for \\x escape")
}
newstr.append(value.toChar)
i += 1
}
else {
newstr.append('\\')
newstr.append(cp.toChar)
}
saw_backslash = false
}
}
}
i += 1
}
if (saw_backslash) newstr.append('\\')
newstr.toString
}
private def die(msg: String) {
throw new IllegalArgumentException(msg)
}
\x
используется для удаления символов ASCII в Python и других языках. В Scala и Java вы можете использовать \u
для выхода из символов Unicode. Поскольку ASCII является подмножеством Unicode (как описано здесь), мы можем использовать unescapeJava
метод (в StringEscapeUtils
) вместе с некоторой простой замены, чтобы добавить \u
бежать характер вместе с 2 - мя ведущими нулями:
import org.apache.commons.lang3.StringEscapeUtils
StringEscapeUtils.unescapeJava(x.replaceAll("""\\x""", """\\u00"""))
Вы также можете использовать регулярное выражение, чтобы найти escape-последовательности и заменить их соответствующим символом ASCII:
val pattern = """\\x([0-9A-F]{2})""".r
pattern.replaceAllIn(x, m => m.group(1) match {
case "5C" => """\\""" //special case for backslash
case hex => Integer.parseInt(hex, 16).toChar.toString
})
Это кажется более быстрым и не требует внешней библиотеки, хотя она по-прежнему может быть медленной для ваших нужд. Вероятно, он также не охватывает некоторые граничные случаи, но может охватывать простые потребности.
Я определенно не эксперт в этом, поэтому может быть лучший способ справиться с этим.