iconv 任何编码为 UTF-8

Posted

技术标签:

【中文标题】iconv 任何编码为 UTF-8【英文标题】:iconv any encoding to UTF-8 【发布时间】:2012-04-07 04:03:28 【问题描述】:

我正在尝试将 iconv 指向一个目录,无论当前编码如何,所有文件都将转换为 UTF-8

我正在使用这个脚本,但您必须指定您要使用的编码。如何让它自动检测当前的编码?

dir_iconv.sh

#!/bin/bash

ICONVBIN='/usr/bin/iconv' # path to iconv binary

if [ $# -lt 3 ]
then
  echo "$0 dir from_charset to_charset"
  exit
fi

for f in $1/*
do
  if test -f $f
  then
    echo -e "\nConverting $f"
    /bin/mv $f $f.old
    $ICONVBIN -f $2 -t $3 $f.old > $f
  else
    echo -e "\nSkipping $f - not a regular file";
  fi
done

终端线

sudo convert/dir_iconv.sh convert/books CURRENT_ENCODING utf8

【问题讨论】:

相关:How to change encoding from Non-ISO extended-ASCII text? 【参考方案1】:

也许你正在寻找enca:

Enca 是一个非常简单的字符集分析器。它检测文本文件的字符集和编码,还可以使用内置转换器或外部库和工具(如 libiconv、librecode 或 cstocs)将它们转换为其他编码。

目前它支持白俄罗斯语、保加利亚语、克罗地亚语、捷克语、爱沙尼亚语、匈牙利语、拉脱维亚语、立陶宛语、波兰语、俄语、斯洛伐克语、斯洛文尼亚语、乌克兰语、中文和一些独立于语言的多字节编码。

请注意,一般来说,当前编码的自动检测是一个困难的过程(相同的字节序列在多种编码中可以是正确的文本)。 enca 根据您告诉它检测的语言使用启发式算法(以限制编码的数量)。您可以使用enconv 到convert text files 进行单一编码。

【讨论】:

您的 Enca 链接无效。这是更新的吗? freecode.com/projects/enca 从那时起,Enca 似乎搬到了 Github。请注意,freecode 站点还链接到不存在的 Gitorious 链接。更新了答案中的链接。 我想知道您的意思是iconv而不是econv,因为我在手册中找不到econv 语法:enca -x utf8 -L mylanguage file.srt. 您的版本中的有效语言列表:enca -l languages ... 但是 UBUNTU 在更新时,我的 enca --version 是 2005 年!如何升级?【参考方案2】:

您可以使用标准的 gnu utils 文件和 awk 获得所需的内容。示例:

file -bi .xsession-errors 给我: "text/plain; charset=us-ascii"

所以file -bi .xsession-errors |awk -F "=" 'print $2' 给我 "us-ascii"

我在这样的脚本中使用它:

CHARSET="$(file -bi "$i"|awk -F "=" 'print $2')"

if [ "$CHARSET" != utf-8 ]; then
  iconv -f "$CHARSET" -t utf8 "$i" -o outfile
fi

【讨论】:

file 使用的启发式方法可能相当粗糙。小心。【参考方案3】:

编译所有这些。进入目录,创建dir2utf8.sh:

#!/bin/bash
# converting all files in a dir to utf8

for f in *
do
  if test -f $f then
    echo -e "\nConverting $f"
    CHARSET="$(file -bi "$f"|awk -F "=" 'print $2')"
    if [ "$CHARSET" != utf-8 ]; then
      iconv -f "$CHARSET" -t utf8 "$f" -o "$f"
    fi
  else
    echo -e "\nSkipping $f - it's a regular file";
  fi
done

【讨论】:

【参考方案4】:

这里是my solution,用于使用recode 和uchardet 放置所有文件:

#!/bin/bash

apt-get -y install recode uchardet > /dev/null
find "$1" -type f | while read FFN # 'dir' should be changed...
do
  encoding=$(uchardet "$FFN")
  echo "$FFN: $encoding"
  enc=`echo $encoding | sed 's#^x-mac-#mac#'`
  set +x
  recode $enc..UTF-8 "$FFN"
done

将其放入convert-dir-to-utf8.sh 并运行:

bash convert-dir-to-utf8.sh /pat/to/my/trash/dir

请注意,sed 是此处用于 mac 编码的解决方法。 许多不常见的编码需要这样的解决方法。

【讨论】:

uchardet 保存了我的脚本 提示:备份您的文件并使用合并工具检查/比较更改。可能会出现问题! recode 除了this fork之外似乎不再维护【参考方案5】:

查看可用于在 linux cli 中进行数据转换的工具:https://www.debian.org/doc/manuals/debian-reference/ch11.en.html

此外,还有一个任务是找出iconv 中可用的完整编码列表。只需运行iconv --list 并发现编码名称与uchardet 工具返回的名称不同(例如:uchardet 中的 x-mac-cyrillic 与iconv 中的 mac-cyrillic)

【讨论】:

【参考方案6】:

enca 命令不适用于我的 GB2312 编码的简体中文文本文件。

相反,我使用以下函数为我转换文本文件。 您当然可以将输出重定向到文件中。

它需要 chardeticonv 命令。

detection_cat () 

    DET_OUT=$(chardet $1);
    ENC=$(echo $DET_OUT | sed "s|^.*: \(.*\) (confid.*$|\1|");
    iconv -f $ENC $1

【讨论】:

【参考方案7】:

第一个答案

#!/bin/bash

find "<YOUR_FOLDER_PATH>" -name '*' -type f -exec grep -Iq .  \; -print0 |
while IFS= read -r -d $'\0' LINE_FILE; do
  CHARSET=$(uchardet $LINE_FILE)
  echo "Converting ($CHARSET) $LINE_FILE"

  # NOTE: Convert/reconvert to utf8. By Questor
  iconv -f "$CHARSET" -t utf8 "$LINE_FILE" -o "$LINE_FILE"

  # NOTE: Remove "BOM" if exists as it is unnecessary. By Questor
  # [Refs.: https://***.com/a/2223926/3223785 ,
  # https://***.com/a/45240995/3223785 ]
  sed -i '1s/^\xEF\xBB\xBF//' "$LINE_FILE"

done
# [Refs.: https://justrocketscience.com/post/handle-encodings ,
# https://***.com/a/9612232/3223785 ,
# https://***.com/a/13659891/3223785 ]

进一步的问题:我不知道我的方法是否最安全。我这样说是因为我注意到某些文件没有正确转换(字符会丢失)或被“截断”。我怀疑这与“iconv”工具或使用“uchardet”工具获得的字符集信息有关。我对presented by @demofly 的解决方案很好奇,因为它可能更安全。

另一个答案

基于@demofly 的回答:

#!/bin/bash

find "<YOUR_FOLDER_PATH>" -name '*' -type f -exec grep -Iq .  \; -print0 |
while IFS= read -r -d $'\0' LINE_FILE; do
  CHARSET=$(uchardet $LINE_FILE)
  REENCSED=`echo $CHARSET | sed 's#^x-mac-#mac#'`
  echo "\"$CHARSET\" \"$LINE_FILE\""

  # NOTE: Convert/reconvert to utf8. By Questor
  recode $REENCSED..UTF-8 "$LINE_FILE" 2> STDERR_OP 1> STDOUT_OP

  STDERR_OP=$(cat STDERR_OP)
  rm -f STDERR_OP
  if [ -n "$STDERR_OP" ] ; then

    # NOTE: Convert/reconvert to utf8. By Questor
    iconv -f "$CHARSET" -t utf8 "$LINE_FILE" -o "$LINE_FILE" 2> STDERR_OP 1> STDOUT_OP

    STDERR_OP=$(cat STDERR_OP)
    rm -f STDERR_OP
  fi

  # NOTE: Remove "BOM" if exists as it is unnecessary. By Questor
  # [Refs.: https://***.com/a/2223926/3223785 ,
  # https://***.com/a/45240995/3223785 ]
  sed -i '1s/^\xEF\xBB\xBF//' "$LINE_FILE"

  if [ -n "$STDERR_OP" ] ; then
    echo "ERROR: \"$STDERR_OP\""
  fi
  STDOUT_OP=$(cat STDOUT_OP)
  rm -f STDOUT_OP
  if [ -n "$STDOUT_OP" ] ; then
    echo "RESULT: \"$STDOUT_OP\""
  fi
done
# [Refs.: https://justrocketscience.com/post/handle-encodings ,
# https://***.com/a/9612232/3223785 ,
# https://***.com/a/13659891/3223785 ]

第三个答案

带有 recode 和 vim 的混合解决方案:

#!/bin/bash

find "<YOUR_FOLDER_PATH>" -name '*' -type f -exec grep -Iq .  \; -print0 |
while IFS= read -r -d $'\0' LINE_FILE; do
  CHARSET=$(uchardet $LINE_FILE)
  REENCSED=`echo $CHARSET | sed 's#^x-mac-#mac#'`
  echo "\"$CHARSET\" \"$LINE_FILE\""

  # NOTE: Convert/reconvert to utf8. By Questor
  recode $REENCSED..UTF-8 "$LINE_FILE" 2> STDERR_OP 1> STDOUT_OP

  STDERR_OP=$(cat STDERR_OP)
  rm -f STDERR_OP
  if [ -n "$STDERR_OP" ] ; then

    # NOTE: Convert/reconvert to utf8. By Questor
    bash -c "</dev/tty vim -u NONE +\"set binary | set noeol | set nobomb | set encoding=utf-8 | set fileencoding=utf-8 | wq\" \"$LINE_FILE\""

  else

    # NOTE: Remove "BOM" if exists as it is unnecessary. By Questor
    # [Refs.: https://***.com/a/2223926/3223785 ,
    # https://***.com/a/45240995/3223785 ]
    sed -i '1s/^\xEF\xBB\xBF//' "$LINE_FILE"

  fi
done

是完美转化次数最多的解决方案。此外,我们没有任何截断的文件。


警告:备份您的文件并使用合并工具检查/比较更改。可能会出现问题! 提示:命令sed -i '1s/^\xEF\xBB\xBF//' "$LINE_FILE"可以在没有它的转换后与合并工具进行初步比较后执行,因为它会导致“差异”。 注意: 使用 find 进行搜索会从给定路径 ("") 及其子文件夹中找到所有非二进制文件。

【讨论】:

两个小提示:我会将&lt;YOUR_FOLDER_PATH&gt; 替换为"$1" 并让最终用户传入文件夹路径。而对于 MacOS 用户,您需要运行:brew install recode uchardet gnu-sed,然后将 sed 更改为 gsed 以使其工作。使用grep -I 删除二进制文件做得很好。高分! 您的建议几乎被完全接受。我没有保留更改“我会将 替换为“$1””,因为我认为以前的方法对更多人来说更清晰。谢谢! = D 你不应该向iconv提供相同的文件用于输入和输出unix.stackexchange.com/questions/10241/…***.com/questions/17872302/… 我读到最好使用inplace iconv iconv -f UTF-32 -t UTF-8 file.csv ***.com/questions/64860/…【参考方案8】:

使用 iconv 和 uchardet (谢谢 farseerfc)

鱼壳

cat your_file  | iconv -f (uchardet your_file ) -t UTF-8

bash 外壳

cat your_file  | iconv -f $(uchardet your_file ) -t UTF-8

如果使用 bash 脚本

#!/usr/bin/bash
for fn in "$@"
do
    iconv < "$fn" -f $(uchardet "$fn") -t utf8
done

@flowinglight 在 ubuntu 组。

【讨论】:

以上是关于iconv 任何编码为 UTF-8的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Linux 中将文件编码转换为 UTF-8

如何在 Linux 中将文件编码转换为 UTF-8

如何在 Linux 中将文件编码转换为 UTF-8

iconv 解决utf-8和gb2312编码转换问题

linuxiconvlatin1转utf8

在Linux如何让更改文件的字符编码