如何从文件中删除所有的变音符号?

53

我有一个文件,其中含有许多带附加符号的元音字母。我需要进行以下替换:

  • 用 a 替换 ā、á、ǎ 和 à。
  • 用 e 替换 ē、é、ě 和 è。
  • 用 i 替换 ī、í、ǐ 和 ì。
  • 用 o 替换 ō、ó、ǒ 和 ò。
  • 用 u 替换 ū、ú、ǔ 和 ù。
  • 用 ü 替换 ǖ、ǘ、ǚ 和 ǜ。
  • 用 A 替换 Ā、Á、Ǎ 和 À。
  • 用 E 替换 Ē、É、Ě 和 È。
  • 用 I 替换 Ī、Í、Ǐ 和 Ì。
  • 用 O 替换 Ō、Ó、Ǒ 和 Ò。
  • 用 U 替换 Ū、Ú、Ǔ 和 Ù。
  • 用 Ü 替换 Ǖ、Ǘ、Ǚ 和 Ǜ。

我知道可以使用以下方式逐个替换:

sed -i 's/ā/a/g' ./file.txt

有没有更有效的方法来替换所有这些内容?


3
sed可能不是最适合这项工作的工具;iconv可能更好。参见:https://dev59.com/9Goy5IYBdhLWcg3wa9bf - Wooble
10个回答

81
如果您查看工具iconv的手册页:

//TRANSLIT
当在 --to-code 后附加字符串 "//TRANSLIT" 时,激活转换。这意味着当一个字符无法在目标字符集中表示时,它可以通过一个或多个类似的外观字符来近似表示。

因此我们可以执行:
kent$  cat test1
    Replace ā, á, ǎ, and à with a.
    Replace ē, é, ě, and è with e.
    Replace ī, í, ǐ, and ì with i.
    Replace ō, ó, ǒ, and ò with o.
    Replace ū, ú, ǔ, and ù with u.
    Replace ǖ, ǘ, ǚ, and ǜ with ü.
    Replace Ā, Á, Ǎ, and À with A.
    Replace Ē, É, Ě, and È with E.
    Replace Ī, Í, Ǐ, and Ì with I.
    Replace Ō, Ó, Ǒ, and Ò with O.
    Replace Ū, Ú, Ǔ, and Ù with U.
    Replace Ǖ, Ǘ, Ǚ, and Ǜ with U.


kent$  iconv -f utf8 -t ascii//TRANSLIT test1
    Replace a, a, a, and a with a.
    Replace e, e, e, and e with e.
    Replace i, i, i, and i with i.
    Replace o, o, o, and o with o.
    Replace u, u, u, and u with u.
    Replace u, u, u, and u with u.
    Replace A, A, A, and A with A.
    Replace E, E, E, and E with E.
    Replace I, I, I, and I with I.
    Replace O, O, O, and O with O.
    Replace U, U, U, and U with U.
    Replace U, U, U, and U with U.

4
除了我只想让标记从ü消失,但不想要变音符外,这个方法很有效。 - Village
Kent,我想为iconv的"the" man页面添加一个直接链接,但是我找到的所有页面都没有包含那个特定的引用。你想要添加你从哪里得到它吗? - Jongware
1
man iconv 可以查看 iconv 的手册页。我当前使用的版本是 iconv (GNU libc) 2.21,但是这个回答是三年前发布的,我不知道当时我使用的是哪个版本。@Jongware - Kent
20
在 macOS 上默认的 iconv(GNU libiconv 1.11)中,使用“echo 'á' | iconv -f utf8 -t ascii//TRANSLIT”会得到“'a”而不是“a”。 - nloveladyallen
关于这个答案的一个侧面说明:当你遇到“_iconv: illegal input sequence at position ..._”错误时,请检查目标文件的字符集。假设你从Microsoft Excel导出了一个CSV文件,运行file -i test2.csv并看到charset=iso-8859-1,那么请使用-f iso-8859-1而不是-f utf8 - Culip
2023年11月,这对我来说相当不错,将罗马尼亚城市名称转换为Numbeo.com所知道的名称。只有四个错误是â^a,例如"T^argoviste"。这是MacOS 14.0上的22 Oct 2009(man page日期)版本。 - undefined

19

这个可能适合你:

sed -i 'y/āáǎàēéěèīíǐìōóǒòūúǔùǖǘǚǜĀÁǍÀĒÉĚÈĪÍǏÌŌÓǑÒŪÚǓÙǕǗǙǛ/aaaaeeeeiiiioooouuuuüüüüAAAAEEEEIIIIOOOOUUUUÜÜÜÜ/' file

有趣的是,如果你在 Mac 上,你需要在命令行中添加 -e 标志。更多信息请参考:https://dev59.com/FWQn5IYBdhLWcg3wiXud - Mr Washington
2
macosx: sed -e 'y/āáǎàçēéěèīíǐìōóǒòūúǔùǖǘǚǜüĀÁǍÀĒÉĚÈĪÍǏÌŌÓǑÒŪÚǓÙǕǗǙǛÜ/aaaaceeeeiiiioooouuuuuuuuuAAAAEEEEIIIIOOOOUUUUUUUUU/' file 注意:出于我的需要,我没有保留ü字符。 - leontalbot
1
“sed”的优点是它几乎无处不在。只需改进版本:-e 'y/āáǎàēéěèīíǐìïōóǒòöūúǔùǖǘǚǜüĀÁǍÀĒÉĚÈĪÍǏÌŌÓǑÒŪÚǓÙǕǗǙǛÜÇçÑñ/aaaaeeeeiiiiiooooouuuuuuuuuAAAAEEEEIIIIOOOOUUUUUUUUUCcNn/' - ATorras
1
添加了在法语中使用的带有折音符号的字符,例如 ê'y/āáǎàâēéěèêīíǐìïîōóǒòöôūúǔùǖǘǚǜüûĀÁǍÀĒÉĚÈÊĪÍǏÌÎŌÓǑÒÔŪÚǓÙǕǗǙǛÜÛÇçÑñ/aaaaaeeeeeiiiiiioooooouuuuuuuuuuAAAAEEEEEIIIIIOOOOOUUUUUUUUUUCcNn/' - Nic3500
1
添加了来自@Nic3500的法语特殊字符,如ê。<br /> 'y/āáǎàâēéěèêêīíǐìïîōóǒòöôūúǔùǖǘǚǜüûĀÁǍÀĒÉĚÈÊËĪÍǏÌÎŌÓǑÒÔŪÚǓÙǕǗǙǛÜÛÇçÑñ/aaaaaeeeeeeiiiiiioooooouuuuuuuuuuAAAAEEEEEEIIIIIOOOOOUUUUUUUUUUCcNn/' - FrViPofm
嗯...重新组织:<br />string1="āáǎàâäçēéěèêëīíǐìîïñōóǒòôöūúǔùûǖǘǚǜĀÁǍÀÂÄÇĒÉĚÈÊËĪÍǏÌÎÏŌÓǑÒÔÖŪÚǓÙǕǗǙǛ"<br />string2="aaaaaaçeeeeeeiiiiiinoooooouuuuuuuuuAAAAAACEEEEEEIIIIIINOOOOOOUUUUUUU"<br />测试:<br />echo $(echo $string1 | sed -e"y/$string1/$string2/") - FrViPofm

14

我喜欢iconv,因为它可以处理所有的重音变体:

cat non-ascii.txt | iconv -f utf8 -t ascii//TRANSLIT//IGNORE > ascii.txt

2
这个程序把 Ángel 转换成了 'angel。:( - Heath Borders
对我来说也是如此,但我更喜欢这个解决方案,即在去除非ASCII字符之后,添加一个sed命令作为“s / [^a-zA-Z] // g”。变成:cat non-ascii.txt | iconv -f utf8 -t ascii//TRANSLIT//IGNORE | sed "s/[^a-zA-Z]//g" > ascii.txt - Djeefther Souza

3

这时就需要使用tr(1)命令。例如:

tr 'āáǎàēéěèīíǐì...' 'aaaaeeeeiii...' <infile >outfile

您可能需要检查/更改您的LANG环境变量以匹配正在使用的字符集。


2
#!/bin/bash
INPUT="$1"
declare -a acc
declare -a noa
acc=('$' 'è' 'ê' 'é' 'À' 'Á' 'Â' 'Ã' 'Ä' 'Å' 'Æ' 'Ç' 'È' 'É' 'Ê' 'Ë' 'Ì' 'Í' 'Î' 'Ï' 'Ð' 'Ñ' 'Ò' 'Ó' 'Ô' 'Õ' 'Ö' 'Ø' 'Ù' 'Ú' 'Û' 'Ü' 'Ý' 'ß' 'à' 'á' 'â' 'ã' 'ä' 'å' 'æ' 'ç' 'è' 'é' 'ê' 'ë' 'ì' 'í' 'î' 'ï' 'ñ' 'ò' 'ó' 'ô' 'õ' 'ö' 'ø' 'ù' 'ú' 'û' 'ü' 'ý' 'ÿ' 'Ā' 'ā' 'Ă' 'ă' 'Ą' 'ą' 'Ć' 'ć' 'Ĉ' 'ĉ' 'Ċ' 'ċ' 'Č' 'č' 'Ď' 'ď' 'Đ' 'đ' 'Ē' 'ē' 'Ĕ' 'ĕ' 'Ė' 'ė' 'Ę' 'ę' 'Ě' 'ě' 'Ĝ' 'ĝ' 'Ğ' 'ğ' 'Ġ' 'ġ' 'Ģ' 'ģ' 'Ĥ' 'ĥ' 'Ħ' 'ħ' 'Ĩ' 'ĩ' 'Ī' 'ī' 'Ĭ' 'ĭ' 'Į' 'į' 'İ' 'ı' 'IJ' 'ij' 'Ĵ' 'ĵ' 'Ķ' 'ķ' 'Ĺ' 'ĺ' 'Ļ' 'ļ' 'Ľ' 'ľ' 'Ŀ' 'ŀ' 'Ł' 'ł' 'Ń' 'ń' 'Ņ' 'ņ' 'Ň' 'ň' 'ʼn' 'Ō' 'ō' 'Ŏ' 'ŏ' 'Ő' 'ő' 'Œ' 'œ' 'Ŕ' 'ŕ' 'Ŗ' 'ŗ' 'Ř' 'ř' 'Ś' 'ś' 'Ŝ' 'ŝ' 'Ş' 'ş' 'Š' 'š' 'Ţ' 'ţ' 'Ť' 'ť' 'Ŧ' 'ŧ' 'Ũ' 'ũ' 'Ū' 'ū' 'Ŭ' 'ŭ' 'Ů' 'ů' 'Ű' 'ű' 'Ų' 'ų' 'Ŵ' 'ŵ' 'Ŷ' 'ŷ' 'Ÿ' 'Ź' 'ź' 'Ż' 'ż' 'Ž' 'ž' 'ſ' 'ƒ' 'Ơ' 'ơ' 'Ư' 'ư' 'Ǎ' 'ǎ' 'Ǐ' 'ǐ' 'Ǒ' 'ǒ' 'Ǔ' 'ǔ' 'Ǖ' 'ǖ' 'Ǘ' 'ǘ' 'Ǚ' 'ǚ' 'Ǜ' 'ǜ' 'Ǻ' 'ǻ' 'Ǽ' 'ǽ' 'Ǿ' 'ǿ');
noa=('S' 'e' 'e' 'e' 'A' 'A' 'A' 'A' 'A' 'A' 'AE' 'C' 'E' 'E' 'E' 'E' 'I' 'I' 'I' 'I' 'D' 'N' 'O' 'O' 'O' 'O' 'O' 'O' 'U' 'U' 'U' 'U' 'Y' 's' 'a' 'a' 'a' 'a' 'a' 'a' 'ae' 'c' 'e' 'e' 'e' 'e' 'i' 'i' 'i' 'i' 'n' 'o' 'o' 'o' 'o' 'o' 'o' 'u' 'u' 'u' 'u' 'y' 'y' 'A' 'a' 'A' 'a' 'A' 'a' 'C' 'c' 'C' 'c' 'C' 'c' 'C' 'c' 'D' 'd' 'D' 'd' 'E' 'e' 'E' 'e' 'E' 'e' 'E' 'e' 'E' 'e' 'G' 'g' 'G' 'g' 'G' 'g' 'G' 'g' 'H' 'h' 'H' 'h' 'I' 'i' 'I' 'i' 'I' 'i' 'I' 'i' 'I' 'i' 'IJ' 'ij' 'J' 'j' 'K' 'k' 'L' 'l' 'L' 'l' 'L' 'l' 'L' 'l' 'l' 'l' 'N' 'n' 'N' 'n' 'N' 'n' 'n' 'O' 'o' 'O' 'o' 'O' 'o' 'OE' 'oe' 'R' 'r' 'R' 'r' 'R' 'r' 'S' 's' 'S' 's' 'S' 's' 'S' 's' 'T' 't' 'T' 't' 'T' 't' 'U' 'u' 'U' 'u' 'U' 'u' 'U' 'u' 'U' 'u' 'U' 'u' 'W' 'w' 'Y' 'y' 'Y' 'Z' 'z' 'Z' 'z' 'Z' 'z' 's' 'f' 'O' 'o' 'U' 'u' 'A' 'a' 'I' 'i' 'O' 'o' 'U' 'u' 'U' 'u' 'U' 'u' 'U' 'u' 'U' 'u' 'A' 'a' 'AE' 'ae' 'O' 'o');

i=0
length=${#INPUT}
while [[ $i -lt $length ]]; do
    char=${INPUT:$i:1};
    #echo $i:$char
    j=0
    for letter in "${acc[@]}"
    do
        if [[ "$letter" == "$char" ]]; then
            char="${noa[$j]}"
        fi
        ((j++))
    done
    ((i++))
    OUTPUT=$OUTPUT$char
done
echo $OUTPUT

这个怎么从文件中读取?谢谢。 - jat

1
如果你和我一样,需要在文件文本的某些特定位置替换重音符号,你可以使用这种正则表达式进行操作。
echo '{"doNotReplaceKey":"bábögêjírù","replaceValueKey":"bábögêjírù","anotherNotReplaceKey":"bábögêjírù"}' \
    | sed -e ':a;s/replaceValueKey":"\([a-zA-Z0-9 -_]*\)[áâàãä]/replaceValueKey":"\1a/g;ta' \
    | sed -e ':a;s/replaceValueKey":"\([a-zA-Z0-9 -_]*\)[éêèë]/replaceValueKey":"\1e/g;ta'  \
    | sed -e ':a;s/replaceValueKey":"\([a-zA-Z0-9 -_]*\)[íîìï]/replaceValueKey":"\1i/g;ta'  \
    | sed -e ':a;s/replaceValueKey":"\([a-zA-Z0-9 -_]*\)[óôòõö]/replaceValueKey":"\1o/g;ta' \
    | sed -e ':a;s/replaceValueKey":"\([a-zA-Z0-9 -_]*\)[úûùü]/replaceValueKey":"\1u/g;ta'

输出

{"doNotReplaceKey":"bábögêjírù","replaceValueKey":"babogejiru","anotherNotReplaceKey":"bábögêjírù"}

1
你可以使用man iso_8859_1(或你的字符集)或od -bc来识别变音符号的八进制表示。然后使用gawk进行替换。
{ gsub(/\344/,"a"; print $0 }

这将用 a 替换 ä


1
你可以使用类似这样的代码:
  sed -e 's/[àâ]/a/g;s/[ọõ]/o/g;s/[í,ì]/i/g;s/[ê,ệ]/e/g' 

只需根据您的需要向[...]添加更多字符即可。

0

如果你想知道哪个解决方案最快:

文本音译:使用tr:5.3 MB/s

文本音译:使用sed:70.3 MB/s

文本音译:使用iconv:35.2 MB/s

因此,sed 'y/[diacritics]/[transliterated]/'命令是迄今为止最快的!

(代码在github.com/pforret/bash_benchmarks上)


0

这可能行不通。因为你的本地环境必须设置好!

使用 locale 来设置 LC_ALL,例如:

export LC_ALL=en_US.iso88591

请注意,完整的语言环境列表可通过以下方式获得:
locale -a

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接