使用 iconv 或 python3 将 utf-8 重新编码为 Latin-1 (ISO-8859-1),保留重音字符
Use iconv or python3 to recode utf-8 to Latin-1 (ISO-8859-1) preserving accented characters
大多数人认为,应该能够更改 UTF-8 的编码
通过简单调用 iconv 将文件转换为 Latin-1 (ISO-8859-1) 编码,例如:
iconv -c -f utf-8 -t ISO-8859-1//TRANSLIT
但是,这无法正确处理重音字符。考虑
例如:
$ echo $LC_ALL
C
$ cat Gonzalez.txt
González, M.
$ file Gonzalez.txt
Gonzalez.txt: UTF-8 Unicode text
$ iconv -c -f utf-8 -t ISO-8859-1//TRANSLIT < Gonzalez.txt > out
$ file out
out: ASCII text
$ cat out
Gonzalez, M.
我尝试了上述的各种变体,但 none 正确处理
带重音的“a”,关键是 Latin-1 确实有带重音的“a”。
的确,uconv
确实处理得当:
$ uconv -x Any-Accents -f utf-8 -t l1 < Gonzalez.txt > out
$ file out
out: ISO-8859 text
正在用 emacs 或
Sublime 正确显示重音符号“a”。使用 -x nfc
.
同样的事情
不幸的是,我的目标环境不允许使用“uconv”的解决方案,
所以我正在寻找使用 iconv 或 Python3.
的简单解决方案
python3 次尝试
到目前为止,我使用 python3 的尝试都没有成功。
例如,以下内容:
import sys
import fileinput # allows file to be specified or else reads from STDIN
for line in fileinput.input():
l=line.encode("latin-1","replace")
sys.stdout.buffer.write(l)
产生:
Gonza?lez, M.
(这是字面上的“?”。)
我已经尝试了各种其他 Python3 的可能性,到目前为止都没有成功。
请注意,我已经查看了关于此主题的大量 SO 问题,但使用 iconv 或 Python3 的答案无法正确处理 Gonzalez.txt。
有两种方法可以在 Unicode 中对 A WITH ACUTE ACCENT 进行编码。
一种是使用组合字符,如图所示,这里使用 Python 的内置 ascii
函数:
>>> ascii('á')
"'\xe1'"
但您也可以在非重音字母后使用组合重音 a
:
>>> ascii('á')
"'a\u0301'"
根据显示的应用程序,这两个变体可能看起来无法区分(在我的终端中,后者看起来有点奇怪,重音太大)。
现在,Latin-1 有一个重音字母 a
,但没有组合重音,所以这就是为什么在使用 errors="replace"
编码时尖音符变成问号的原因。
幸运的是,您可以在两种变体之间自动切换。
无需赘述(此处有 许多 细节),Unicode 定义了两种规范化形式,称为 composed 和 decomposed,分别缩写为NFC和NFD。
在 Python 中,您可以使用标准库模块 unicodedata
:
>>> import unicodedata as ud
>>> ascii(ud.normalize('NFD', 'á'))
"'a\u0301'"
>>> ascii(ud.normalize('NFC', 'á'))
"'\xe1'"
在您的具体情况下,您可以将输入字符串转换为 NFC 形式,这将增加 Latin-1 字符的覆盖范围:
>>> n = 'Gonza\u0301lez, M.'
>>> print(n)
González, M.
>>> n.encode('latin1', errors='replace')
b'Gonza?lez, M.'
>>> ud.normalize('NFC', n).encode('latin1', errors='replace')
b'Gonz\xe1lez, M.'
大多数人认为,应该能够更改 UTF-8 的编码 通过简单调用 iconv 将文件转换为 Latin-1 (ISO-8859-1) 编码,例如:
iconv -c -f utf-8 -t ISO-8859-1//TRANSLIT
但是,这无法正确处理重音字符。考虑 例如:
$ echo $LC_ALL
C
$ cat Gonzalez.txt
González, M.
$ file Gonzalez.txt
Gonzalez.txt: UTF-8 Unicode text
$ iconv -c -f utf-8 -t ISO-8859-1//TRANSLIT < Gonzalez.txt > out
$ file out
out: ASCII text
$ cat out
Gonzalez, M.
我尝试了上述的各种变体,但 none 正确处理 带重音的“a”,关键是 Latin-1 确实有带重音的“a”。
的确,uconv
确实处理得当:
$ uconv -x Any-Accents -f utf-8 -t l1 < Gonzalez.txt > out
$ file out
out: ISO-8859 text
正在用 emacs 或
Sublime 正确显示重音符号“a”。使用 -x nfc
.
不幸的是,我的目标环境不允许使用“uconv”的解决方案, 所以我正在寻找使用 iconv 或 Python3.
的简单解决方案python3 次尝试
到目前为止,我使用 python3 的尝试都没有成功。 例如,以下内容:
import sys
import fileinput # allows file to be specified or else reads from STDIN
for line in fileinput.input():
l=line.encode("latin-1","replace")
sys.stdout.buffer.write(l)
产生:
Gonza?lez, M.
(这是字面上的“?”。)
我已经尝试了各种其他 Python3 的可能性,到目前为止都没有成功。
请注意,我已经查看了关于此主题的大量 SO 问题,但使用 iconv 或 Python3 的答案无法正确处理 Gonzalez.txt。
有两种方法可以在 Unicode 中对 A WITH ACUTE ACCENT 进行编码。
一种是使用组合字符,如图所示,这里使用 Python 的内置 ascii
函数:
>>> ascii('á')
"'\xe1'"
但您也可以在非重音字母后使用组合重音 a
:
>>> ascii('á')
"'a\u0301'"
根据显示的应用程序,这两个变体可能看起来无法区分(在我的终端中,后者看起来有点奇怪,重音太大)。
现在,Latin-1 有一个重音字母 a
,但没有组合重音,所以这就是为什么在使用 errors="replace"
编码时尖音符变成问号的原因。
幸运的是,您可以在两种变体之间自动切换。
无需赘述(此处有 许多 细节),Unicode 定义了两种规范化形式,称为 composed 和 decomposed,分别缩写为NFC和NFD。
在 Python 中,您可以使用标准库模块 unicodedata
:
>>> import unicodedata as ud
>>> ascii(ud.normalize('NFD', 'á'))
"'a\u0301'"
>>> ascii(ud.normalize('NFC', 'á'))
"'\xe1'"
在您的具体情况下,您可以将输入字符串转换为 NFC 形式,这将增加 Latin-1 字符的覆盖范围:
>>> n = 'Gonza\u0301lez, M.'
>>> print(n)
González, M.
>>> n.encode('latin1', errors='replace')
b'Gonza?lez, M.'
>>> ud.normalize('NFC', n).encode('latin1', errors='replace')
b'Gonz\xe1lez, M.'