我使用curl
获取一些网址响应,它是JSON响应,它包含unicode转义的国家字符,例如 \u0144 (ń)
和 \u00f3 (ó)
< / strong>即可。
如何将它们转换为 UTF-8 或任何其他编码以保存到文件中?
答案 0 :(得分:38)
可能有点难看,但echo -e
应该这样做:
echo -en "$(curl $URL)"
-e
解释转义,-n
会抑制换行符echo
通常会添加的内容。
注意:\u
转义功能适用于bash内置echo
,但不适用于/usr/bin/echo
。
正如评论中指出的那样,这是bash 4.2+,4.2.x有一个错误处理0x00ff / 17值(0x80-0xff)。
答案 1 :(得分:33)
我发现JDK的native2ascii是最好的方法:
native2ascii -encoding UTF-8 -reverse src.txt dest.txt
详细说明如下:http://docs.oracle.com/javase/1.5.0/docs/tooldocs/windows/native2ascii.html
<强>更新强> 自JDK9以来不再可用:https://bugs.openjdk.java.net/browse/JDK-8074431
答案 2 :(得分:30)
我不知道您使用的是哪种发行版,但应包含 uni2ascii 。
$ sudo apt-get install uni2ascii
它只依赖于libc6,所以它是一个轻量级的解决方案(un2ascii i386 4.18-2在Ubuntu上是55 kB)!
然后使用它:
$ echo 'Character 1: \u0144, Character 2: \u00f3' | ascii2uni -a U -q
Character 1: ń, Character 2: ó
答案 3 :(得分:19)
假设\u
后面总是紧跟4个十六进制数字:
#!/usr/bin/perl
use strict;
use warnings;
binmode(STDOUT, ':utf8');
while (<>) {
s/\\u([0-9a-fA-F]{4})/chr(hex($1))/eg;
print;
}
binmode
将标准输出置于UTF-8模式。 s...
命令替换每个出现的\u
,后跟4个十六进制数字和相应的字符。 e
后缀导致替换被计算为表达式而不是被视为字符串; g
表示要替换所有出现而不仅仅是第一次出现。
您可以将上述内容保存到$PATH
中某个位置的文件中(不要忘记chmod +x
)。它将标准输入(或命令行上指定的一个或多个文件)过滤为标准输出。
同样,这假设表示始终是\u
,后跟正好4个十六进制数字。有更多的Unicode字符可以用这种方式表示,但我假设\u12345
表示Unicode字符0x1234(ETHIOPIC SYLLABLE SEE)后跟数字5
。
在C语法中,通用字符名称是\u
后跟恰好4个十六进制数字,或\U
后跟恰好8个十六进制数字。我不知道你的JSON响应是否使用相同的方案。你应该知道它是如何(或是否)编码基本多语种平面之外的Unicode字符(前2个 16 字符)。
答案 4 :(得分:10)
不要依赖正则表达式:JSON有一些带有\u
转义和非BMP代码点的奇怪转角情况。 (具体来说,JSON将使用两个 \u
转义编码一个代码点。如果假设1转义序列转换为1个代码点,那么你就注定了这样的文本。
使用您选择的语言的完整JSON解析器更加强大:
$ echo '["foo bar \u0144\n"]' | python -c 'import json, sys; sys.stdout.write(json.load(sys.stdin)[0].encode("utf-8"))'
这真的只是将数据提供给这个简短的python脚本:
import json
import sys
data = json.load(sys.stdin)
data = data[0] # change this to find your string in the JSON
sys.stdout.write(data.encode('utf-8'))
您可以将其保存为foo.py
并将其称为curl ... | foo.py
在此问题中打破大多数其他尝试的示例是"\ud83d\udca3"
:
% printf '"\\ud83d\\udca3"' | python2 -c 'import json, sys; sys.stdout.write(json.load(sys.stdin)[0].encode("utf-8"))'; echo
# echo will result in corrupt output:
% echo -e $(printf '"\\ud83d\\udca3"')
"������"
# native2ascii won't even try (this is correct for its intended use case, however, just not ours):
% printf '"\\ud83d\\udca3"' | native2ascii -encoding utf-8 -reverse
"\ud83d\udca3"
答案 5 :(得分:8)
使用/usr/bin/printf "\u0160ini\u010di Ho\u0161i - A\u017e sa skon\u010d\u00ed zima"
进行正确的unicode-to-utf8转换。
答案 6 :(得分:3)
现在我有了最好的答案!使用jq
Windows:
type in.json | jq > out.json
Lunix:
cat in.json | jq > out.json
使用perl / python的答案肯定更快。如果没有参数,它将格式化json并将\ uXXXX转换为utf8。它也可以用于执行json查询。很好的工具!
答案 7 :(得分:1)
序言:对该问题的提升答案中没有一个解决了Telegram-bot-bash中的longstanding issue问题。只有Thanatos的python解决方案有效!
这是因为JSON将使用两个\ u转义符对一个代码点进行编码
在这里您会找到{strong>两个来代替echo -e
和printf '%s'
PURE bash变体作为函数。粘贴到脚本顶部,然后用它在bash中解码JSON字符串:
#!/bin/bash
#
# pure bash implementaion, done by KayM (@gnadelwartz)
# see https://stackoverflow.com/a/55666449/9381171
JsonDecode() {
local out="$1"
local remain=""
local regexp='(.*)\\u[dD]([0-9a-fA-F]{3})\\u[dD]([0-9a-fA-F]{3})(.*)'
while [[ "${out}" =~ $regexp ]] ; do
# match 2 \udxxx hex values, calculate new U, then split and replace
local W1="$(( ( 0xd${BASH_REMATCH[2]} & 0x3ff) <<10 ))"
local W2="$(( 0xd${BASH_REMATCH[3]} & 0x3ff ))"
U="$(( ( W1 | W2 ) + 0x10000 ))"
remain="$(printf '\\U%8.8x' "${U}")${BASH_REMATCH[4]}${remain}"
out="${BASH_REMATCH[1]}"
done
echo -e "${out}${remain}"
}
# Some tests ===============
$ JsonDecode 'xxx \ud83d\udc25 xxxx' -> xxx xxxx
$ JsonDecode '\ud83d\udc25' ->
$ JsonDecode '\u00e4 \u00e0 \u00f6 \u00f4 \u00fc \u00fb \ud83d\ude03 \ud83d\ude1a \ud83d\ude01 \ud83d\ude02 \ud83d\udc7c \ud83d\ude49 \ud83d\udc4e \ud83d\ude45 \ud83d\udc5d \ud83d\udc28 \ud83d\udc25 \ud83d\udc33 \ud83c\udf0f \ud83c\udf89 \ud83d\udcfb \ud83d\udd0a \ud83d\udcec \u2615 \ud83c\udf51'
ä à ö ô ü û ☕
# decode 100x string with 25 JSON UTF-16 vaules
$ time for x in $(seq 1 100); do JsonDecode '\u00e4 \u00e0 \u00f6 \u00f4 \u00fc \u00fb \ud83d\ude03 \ud83d\ude1a \ud83d\ude01 \ud83d\ude02 \ud83d\udc7c \ud83d\ude49 \ud83d\udc4e \ud83d\ude45 \ud83d\udc5d \ud83d\udc28 \ud83d\udc25 \ud83d\udc33 \ud83c\udf0f \ud83c\udf89 \ud83d\udcfb \ud83d\udd0a \ud83d\udcec \u2615 \ud83c\udf51' >/dev/null ; done
real 0m2,195s
user 0m1,635s
sys 0m0,647s
具有Thanatos Phyton变体的MIXED 解决方案:
# usage: JsonDecode "your bash string containing \uXXXX extracted from JSON"
JsonDecode() {
# wrap string in "", replace " by \"
printf '"%s\\n"' "${1//\"/\\\"}" |\
python -c 'import json, sys; sys.stdout.write(json.load(sys.stdin).encode("utf-8"))'
}
-
针对那些提倡其他提升姿势的人的测试用例将起作用:
# test=' ❤️ ' from JSON
$ export test='\uD83D\uDE01 \uD83D\uDE18 \u2764\uFE0F \uD83D\uDE0A \uD83D\uDC4D'
$ printf '"%s\\n"' "${test}" | python -c 'import json, sys; sys.stdout.write(json.load(sys.stdin).encode("utf-8"))' >phyton.txt
$ echo -e "$test" >echo.txt
$ cat -v phyton.txt
M-pM-^_M-^XM-^A M-pM-^_M-^XM-^X M-bM-^]M-$M-oM-8M-^O M-pM-^_M-^XM-^J M-pM-^_M-^QM-^M
$ cat -v echo.txt
M-mM- M-=M-mM-8M-^A M-mM- M-=M-mM-8M-^X M-bM-^]M-$M-oM-8M-^O M-mM- M-=M-mM-8M-^J M-mM- M-=M-mM-1M-^M
您可以轻松地看到输出是不同的。其他提升的解决方案为JSON字符串提供的错误输出与echo -e
相同:
$ ascii2uni -a U -q >uni2ascii.txt <<EOF
$test
EOF
$ cat -v uni2ascii.txt
M-mM- M-=M-mM-8M-^A M-mM- M-=M-mM-8M-^X M-bM-^]M-$M-oM-8M-^O M-mM- M-=M-mM-8M-^J M-mM- M-=M-mM-1M-^M
$ printf "$test\n" >printf.txt
$ cat -v printf.txt
M-mM- M-=M-mM-8M-^A M-mM- M-=M-mM-8M-^X M-bM-^]M-$M-oM-8M-^O M-mM- M-=M-mM-8M-^J M-mM- M-=M-mM-1M-^M
$ echo "$test" | iconv -f Unicode >iconf.txt
$ cat -v iconf.txt
M-gM-^UM-^\M-cM-!M-^DM-dM-^PM-3M-gM-^UM-^\M-dM-^UM-^DM-cM-^DM-0M-eM-0M- M-dM-^QM-5M-cM-^LM-8M-eM-1M-^DM-dM-^QM-5M-cM-^EM-^EM-bM-^@M-8M-gM-^UM-^\M-cM-^\M-2M-cM-^PM-6M-gM-^UM-^\M-dM-^UM-^FM-dM-^XM-0M-eM-0M- M-dM-^QM-5M-cM-^LM-8M-eM-1M-^DM-dM-^QM-5M-cM-^AM-^EM-bM-^AM-^AM-gM-^UM-^\M-cM-!M-^DM-dM-^PM-3M-gM-^UM-^\M-dM-^MM-^DM-dM-^PM-4r
答案 8 :(得分:-1)
iconv -f Unicode fullOrders.csv > fullOrders-utf8.csv
答案 9 :(得分:-1)
使用POSIX要求的b
转换说明符:
下面将支持附加的转换说明符
b
。该参数应视为可以包含反斜杠转义序列的字符串。
— http://pubs.opengroup.org/onlinepubs/9699919799/utilities/printf.html
expand_escape_sequences() {
printf %b "$1"
}
测试:
s='\u0160ini\u010di Ho\u0161i - A\u017e sa skon\u010d\u00ed zima A percent sign % OK?'
expand_escape_sequences "$s"
# output: Šiniči Hoši - Až sa skončí zima A percent sign % OK?
注意:如果删除%b
格式说明符,则百分号将引起类似以下错误:
-bash: printf: `O': invalid format character
与两个bash的内置测试成功printf
和/usr/bin/printf
在我的Linux发行版(Fedora的29)。
<强> UPDATE 2019年4月17日强>:我的解决办法假定Unicode转义像\uxxxx
和\Uxxxxxxxx
; BMP以外的unicode字符需要后者。然而,OP的问题涉及到一个JSON流。 JSON的Unicode转义序列使用UTF16,这需要超过所述BMP代理对
考虑Unicode字符('GRINNING FACE WITH SMILING EYES' (U+1F601))。该字符的\U
转义序列为:\U0001F601
。可以使用授权的POSIX打印%b
说明符就像这样:
printf %b '\U0001F601'
# Prints as expected
然而,在JSON此字符的转义序列涉及一个UTF16代理对:\uD83D\uDE01
对于在外壳层操作JSON流,jq
工具非常棒:
echo '["\uD83D\uDE01"]' | jq .
# Prints [""] as expected
因此我现在考虑撤回我的回答并赞同使用的斯密特Johnth的回答jq
为最佳答案。
答案 10 :(得分:-2)
适用于Windows,也适用于* nix。使用python 2。
#!/usr/bin/env python
from __future__ import unicode_literals
import sys
import json
import codecs
def unescape_json(fname_in, fname_out):
with file(fname_in, 'rb') as fin:
js = json.load(fin)
with codecs.open(fname_out, 'wb', 'utf-8') as fout:
json.dump(js, fout, ensure_ascii=False)
def usage():
print "Converts all \\uXXXX codes in json into utf-8"
print "Usage: .py infile outfile"
sys.exit(1)
def main():
try:
fname_in, fname_out = sys.argv[1:]
except Exception:
usage()
unescape_json(fname_in, fname_out)
print "Done."
if __name__ == '__main__':
main()