如何正确解码从 IMAP 服务器获取的 utf7 文件名

如何正确解码从 IMAP 服务器获取的 utf7 文件名

我有一些从 IMAP 服务器下载的目录。

例子:

$ find . -maxdepth 1
.
./&BCEEPwQwBDw-
./&BCMENAQwBDsENQQ9BD0ESwQ1-
./inbox
./&BCcENQRABD0EPgQyBDgEOgQ4-
./&BB4EQgQ,BEAEMAQyBDsENQQ9BD0ESwQ1-
./&BBgEQQRFBD4ENARPBEkEOAQ1-
./Archive

这些是以 UTF-7 编码的西里尔字母名称。据我了解,utf-7编码单元都是有效的Unicode代码点<127,同时也是有效的ASCII。这意味着我可以在任何我想要的地方复制、粘贴、管道和cat它们。

我们来做一下转换:

$ ls | iconv -f utf7 -t utf8
&BB4EQgQ,BEAEMAQyBDsENQQ9BD0ESwQ1-/
&BBgEQQRFBD4ENARPBEkEOAQ1-/
&BCEEPwQwBDw-/
&BCMENAQwBDsENQQ9BD0ESwQ1-/
&BCcENQRABD0EPgQyBDgEOgQ4-/
Archive/
inbox/

瓦?没有效果?iconv -l列出 utf-7 和 utf-8。

怎么了?

答案1

将西里尔字母从 UTF8 转换为 UTF7 的快速测试

echo 'Here we go. Це коротке речення' | iconv -f utf-8 -t utf-7
Here we go. +BCYENQ +BDoEPgRABD4EQgQ6BDU +BEAENQRHBDUEPQQ9BE8

读一UTF7 的说明编码 我可以看到(粗略地说)每个编码字符串前面必须带有+.您的 UTF7 目录列表中没有这样的前缀。

现在,正如您所看到的,将提取的数据中的 转换为 不会生成有效的代码点&+

echo '&BB4EQgQ,BEAEMAQyBDsENQQ9BD0ESwQ1-/' | tr '&' + | iconv -f utf-7 -t utf-8
От
iconv: (stdin):1:2: cannot convert

但是,如果您采用文件名本身,一旦切换到 ,您就会得到有效的&转换+

echo '&BCMENAQwBDsENQQ9BD0ESwQ1-' | tr '&' + | iconv -f utf-7 -t utf-8
Удаленные

答案2

本质上,这个问题是不恰当的。问题是 IMAP (ab) 使用 utf-7。它几乎是 utf-7,但又不完全是。最终我通过使用 php 文档注释中的 php 代码解决了我的问题:

imap-utf7 的 PHP 文档

答案3

有一个 Perl 模块用于在 IMAP 的修改后的 UTF-7 和 UTF-8 或其他编码之间进行解码(或编码):编码::IMAPUTF7。这使得直接在命令行解码变得非常容易。

默认情况下通常不安装它。要将其安装在基于 Debian 的系统(Ubuntu 等)上:

sudo apt install libencode-imaputf7-perl

或者在 MacOS 上:

cpanp i Encode::IMAPUTF7

将 Bash 终端中当前目录下的所有文件或文件夹重命名为 UTF-8 的单行示例:

find . -depth -name '*&*' | while read x; do new=$(perl -CSA -MEncode::IMAPUTF7 -le 'print Encode::IMAPUTF7::decode(\"IMAP-UTF-7\", shift)' "$x") && mv -v "$x" "$new"; done

或者为了可读性分成更多行:

find . -depth -name '*&*' \
| while read x; do
    new=$(perl -CSA -MEncode::IMAPUTF7 -le 'print Encode::IMAPUTF7::decode(\"IMAP-UTF-7\", shift)' "$x") \
      && mv -v "$x" "$new";
  done

答案4

在最近的 GNU 系统上至少iconv支持一种UTF-7-IMAP编码。ls尽管换行符不是有效字符,但您无法将其输出提供给它:

$ ls | iconv -f UTF-7-IMAP
Archiveiconv: illegal input sequence at position 7

使用 时-c,它会忽略无法解码的字符:

$ ls | iconv -cf UTF-7-IMAP
ArchiveОтправленныеИсходящиеЧерновикиСпамУдаленныеinbox

或者您可以将每个文件名单独提供给iconv

$ for f in *; do printf %s "$f" | iconv -f UTF-7-IMAP; echo; done
Archive
Отправленные
Исходящие
Черновики
Спам
Удаленные
inbox

或者做:

$ printf '%s&AAo-' * | iconv -f UTF-7-IMAP
Archive
Отправленные
Исходящие
Черновики
Спам
Удаленные
inbox

&AAo-换行符的UTF-7-IMAP编码在哪里。

大多数编程语言都有标准iconv(3)接口的绑定。例如,在perl

$ perl -MText::Iconv -le '$c = Text::Iconv->new(qw(UTF-7-IMAP UTF-8));
                          print $c->convert($_) for @ARGV' -- *
Archive
Отправленные
Исходящие
Черновики
Спам
Удаленные
inbox

因此,您可以使用perl's重命名这些文件rename(此处使用的是 File::Rename 2.0.1 中的文件,请注意 's 有多种变体和版本rename):

$ rename -n -- '
    use Text::Iconv;
    our $c //= Text::Iconv->new(qw(UTF-7-IMAP UTF-8));
    $_ = $c->convert($_)' *
rename(&BB4EQgQ,BEAEMAQyBDsENQQ9BD0ESwQ1-, Отправленные)
rename(&BBgEQQRFBD4ENARPBEkEOAQ1-, Исходящие)
rename(&BCcENQRABD0EPgQyBDgEOgQ4-, Черновики)
rename(&BCEEPwQwBDw-, Спам)
rename(&BCMENAQwBDsENQQ9BD0ESwQ1-, Удаленные)

相关内容