【问题标题】:Windows-1252 to UTF-8 encodingWindows-1252 到 UTF-8 编码
【发布时间】:2022-04-23 18:41:37
【问题描述】:

我已将某些文件从 Windows 机器复制到 Linux 机器。所以所有的 Windows 编码(windows-1252)文件都需要转换为 UTF-8。不应更改已在 UTF-8 中的文件。我打算为此使用recode 实用程序。如何指定 recode 实用程序只转换 windows-1252 编码文件而不转换 UTF-8 文件?

recode的使用示例:

recode windows-1252.. myfile.txt

这会将myfile.txt 从 windows-1252 转换为 UTF-8。在这样做之前,我想知道 myfile.txt 实际上是 windows-1252 编码的,而不是 UTF-8 编码的。否则,我相信这会损坏文件。

【问题讨论】:

  • 不再知道文本的字符集和编码 is 损坏(即元数据损坏)。

标签: encoding utf-8 character-encoding data-conversion windows-1252


【解决方案1】:

iconv -f WINDOWS-1252 -t UTF-8 filename.txt

【讨论】:

  • 它看起来像 iconv 输出到 STDOUT,所以你可能想要重定向它,例如... > filename-utf8.txt
  • 请注意,如果文件已经是 UTF8,这将很高兴地对其进行双重编码,从而使您无法阅读。
【解决方案2】:

您希望 recode 如何知道文件是 Windows-1252?理论上,我相信 any 文件是有效的 Windows-1252 文件,因为它将每个可能的字节映射到一个字符。

现在肯定有一些特征强烈建议它是 UTF-8 - 例如,如果它以 UTF-8 BOM 开头 - 但它们不会是确定的。

一种选择是首先检测它是否实际上是一个完全有效的 UTF-8 文件,我想......再说一遍,这只是建议性的。

我不熟悉重新编码工具本身,但您可能想看看它是否能够将文件重新编码为 same 编码 - 如果您使用无效文件执行此操作(即包含无效 UTF-8 字节序列的序列)它很可能将无效序列转换为问号或类似的东西。此时,您可以通过将文件重新编码为 UTF-8 并查看输入和输出是否相同来检测文件是有效的 UTF-8。

或者,以编程方式执行此操作,而不是使用重新编码实用程序 - 例如,在 C# 中它会非常简单。

只是重申一下:所有这些都是启发式的。如果您真的不知道文件的编码,那么没有什么可以 100% 准确地告诉您。

【讨论】:

  • 有几个字节 cp1252 没有映射到字符:0x81、0x8D、0x8F、0x90、0x9D。然而,这一点是成立的。我不会尝试批量转换来自多个不同来源的文件的编码。
  • ISO-8859-1 将每个字节映射到一个字符,80..9F 范围是 C1 控制字符。在 Java 中,我可以使用 ISO-8859-1 将 00..FF 范围内的每个字节解码为字符串,然后重新编码以取回原始字节。当我尝试使用 windows-1252 时,我得到列出的值 bobince 的垃圾。这让我很吃惊;我认为它会用 ISO-8859-1 中的相应控制字符来填补这些空白。
  • @AlanMoore:您为什么希望它使用来自不同编码的字符来填补空白? Windows-1252 和 ISO-8859-1 不是一回事,尽管人们(显然你也是)认为它们是。
  • 我知道它们不一样,但 cp1252 通常被描述为与 Latin-1 相同,但大多数无用的控制字符被替换为有用的打印字符。如果 Microsoft 真的从 Latin-1 开始并按照描述所暗示的那样对其进行了调整,我希望剩余的字节映射到那些相同的控制字符。但事实证明,这两种编码几乎是并行发展的(有点),我的假设让我和 Umption 大为恼火。 :-/
  • @JCoombs:如果您不知道编码,最好不要将其视为文本。
【解决方案3】:

这是我对类似问题给出的另一个答案的转录:

如果将 utf8_encode() 应用于已经是 UTF8 的字符串,它将返回一个乱码的 UTF8 输出。

我创建了一个函数来解决所有这些问题。它被称为 Encoding::toUTF8()。

你不需要知道你的字符串的编码是什么。它可以是 Latin1 (iso 8859-1)、Windows-1252 或 UTF8,或者字符串可以混合使用它们。 Encoding::toUTF8() 会将所有内容都转换为 UTF8。

我这样做是因为一项服务向我提供了一个混乱的数据源,将 UTF8 和 Latin1 混合在同一个字符串中。

用法:

$utf8_string = Encoding::toUTF8($utf8_or_latin1_or_mixed_string);

$latin1_string = Encoding::toLatin1($utf8_or_latin1_or_mixed_string);

下载:

https://github.com/neitanod/forceutf8

更新:

我已经包含了另一个函数,Encoding::fixUFT8(),它将修复每个看起来乱码的 UTF8 字符串。

用法:

$utf8_string = Encoding::fixUTF8($garbled_utf8_string);

例子:

echo Encoding::fixUTF8("Fédération Camerounaise de Football");
echo Encoding::fixUTF8("Fédération Camerounaise de Football");
echo Encoding::fixUTF8("FÃÂédÃÂération Camerounaise de Football");
echo Encoding::fixUTF8("Fédération Camerounaise de Football");

将输出:

Fédération Camerounaise de Football
Fédération Camerounaise de Football
Fédération Camerounaise de Football
Fédération Camerounaise de Football

更新:我已将函数 (forceUTF8) 转换为名为 Encoding 的类上的一系列静态函数。新函数是 Encoding::toUTF8()。

【讨论】:

  • 嗨塞巴斯蒂安。如果我有一个 SQL 导出,我如何通过你的函数解析文件?是否有您编写的独立脚本可以在fixutf8 input.sql >output.sql 形式的命令行中调用,或者您能否帮助我将您的 php 转换为 cli 脚本?
  • 最简单最短的方法是:<?php /*require library here*/ ; file_put_contents("fixed_file.sql", Encoding::fixUTF8(file_get_contents("broken_file.sql")));?>
  • 这太棒了。我喜欢它!
【解决方案4】:

没有通用的方法可以判断文件是否使用特定编码进行编码。请记住,编码只不过是文件中的位应如何映射到字符的“协议”。

如果您不知道哪些文件实际上已经用 UTF-8 编码,哪些文件用 windows-1252 编码,则必须检查所有文件并自己找出答案。在最坏的情况下,这可能意味着您必须使用两种编码中的任何一种打开它们中的每一个,并查看它们是否“看起来”正确——即所有字符都正确显示。当然,您可以使用工具支持来做到这一点,例如,如果您确定某些字符包含在 windows-1252 与 UTF-8 中具有不同映射的文件中,您可以为它们 grep在通过 Seva Akekseyev 提到的“iconv”运行文件之后。

如果您知道文件实际上只包含在 UTF-8 和 windows-1252 中编码相同的字符,那么另一个幸运的情况是。在这种情况下,当然,你已经完成了。

【讨论】:

  • 这是不正确的。有用于检测文件编码的linux utils
  • Linux utils: file 不要总是猜出正确的编码。
【解决方案5】:

如果你想在一个命令中重命名多个文件——假设你想转换所有*.txt文件——这里是命令:

find . -name "*.txt" -exec iconv -f WINDOWS-1252 -t UTF-8 {} -o {}.ren \; -a -exec mv {}.ren {} \;

【讨论】:

  • 这会将所有文件转换为 UTF-8 而不考虑它们的编码,并且会弄乱已经在 UTF-8 中的文件,并且 不是 OP想要
【解决方案6】:

使用 iconv 命令。

要确保文件位于 Windows-1252 中,请在记事本(在 Windows 下)中打开它,然后单击另存为。记事本建议将当前编码作为默认编码;如果它是 Windows-1252(或任何 1 字节代码页,就此而言),它会说“ANSI”。

【讨论】:

  • 打开每个文件将是一个详尽的过程。我想对大量文件进行转换。有没有其他方法可以做到这一点?
  • 文件是什么语言的? Windows-1252 和 UTF-8 之间的区别仅体现在非 ASCII 字符上,即。 e.关于国家的。任何文件都是有效的 Windows-1252 文件,但如果不查看内容并检查字符在目标语言中是否有意义,则无法判断它是否真的是 Windows-1252。如果文件没有扩展字符,那么转换将是微不足道的,您不必费心。
  • 另外:你可以验证 UTF-8。甚至 iconv 也可以做到这一点——将文件从 UTF-8 转换为 UTF-16 并返回;如果它与原始文件不同,则不是 UTF-8。使用创意流水线可能很容易做到。
  • 在你开始之前,做一些统计。大量文件中有多少确实需要转换?
【解决方案7】:

您可以使用记事本++ 等编辑器更改文件的编码。只需转到编码并选择您想要的。

我一直更喜欢 Windows 1252

【讨论】:

  • Notepad++ 是一个仅限 Windows 的工具,但问题是关于 Linux 的。
  • @parsley “我已经从 Windows 机器复制了某些文件”意味着也可以访问 Windows 机器。他可以使用单个菜单选项将所有文件或所有文件的副本转换为所有文件,然后再将它们发送到他的 Linux 机器。您可以恢复反对票。谢谢
  • Windows-1252 或 ISO-8859-1 在 Unicode 世界中总是一个坏主意。在系统之间共享文件成为一个问题,因为许多应用程序假定文件始终采用 UTF-8。此外,这不适合大量转换大量文件
【解决方案8】:

如果您确定您的文件是 UTF-8 或 Windows 1252(或 Latin1),您可以利用这样一个事实:如果您尝试转换无效文件,重新编码将退出并出现错误。

虽然 utf8 是有效的 Win-1252,但反之则不然:win-1252 不是有效的 UTF-8。所以:

recode utf8..utf16 <unknown.txt >/dev/null || recode cp1252..utf8 <unknown.txt >utf8-2.txt

将为所有 cp1252 文件输出错误,然后继续将它们转换为 UTF8。

我会将它包装到一个更干净的 bash 脚本中,为每个转换后的文件保留备份。

在进行字符集转换之前,您可能希望首先确保所有文件中的行尾一致。否则,recode 会因此而报错,并且可能会转换已经是 UTF8 的文件,但只是有错误的行尾。

【讨论】:

  • 只有字节值 00-7F 在 Windows-1252 和 UTF-8 中完全相同。字节值 80-FF 在 Windows-1252 和 UTF-8 中具有不同的含义。所以说“utf8 is valid Win-1252”仅适用于字节 00-7F。
  • 它们显然具有不同的“含义”,但 UTF8 文件中的所有字节都可以是“有效”(即使是无意义的)CP1252 字符。无论如何,上述方法在实践中对我来说效果很好。
  • 其实CP1252中有5个字节值是官方未定义但在UTF-8中有意义的:0x81、0x8D、0x8F、0x90和0x9D。但是,Microsoft API 在文本转换期间将它们映射到 C1 控制代码。
  • 伙计们,UTF8 并不总是映射到单个字节甚至 2 个字节,以 € 为例。 i18nqa.com/debug/utf8-debug.html
  • @Jay:是的,当然不是。但问题是关于从 cp1252 转换为 UTF8,而不是相反。
【解决方案9】:

这个脚本在 Win10/PS5.1 CP1250 到 UTF-8 上为我工作

Get-ChildItem -Include *.php -Recurse | ForEach-Object {
    $file = $_.FullName

    $mustReWrite = $false
    # Try to read as UTF-8 first and throw an exception if
    # invalid-as-UTF-8 bytes are encountered.
    try
    {
        [IO.File]::ReadAllText($file,[Text.Utf8Encoding]::new($false, $true))
    }
    catch [System.Text.DecoderFallbackException]
    {
        # Fall back to Windows-1250
        $content = [IO.File]::ReadAllText($file,[Text.Encoding]::GetEncoding(1250))
        $mustReWrite = $true
    }

    # Rewrite as UTF-8 without BOM (the .NET frameworks' default)
    if ($mustReWrite)
    {
        Write "Converting from 1250 to UTF-8"
        [IO.File]::WriteAllText($file, $content)
    }
    else
    {
        Write "Already UTF-8-encoded"
    }
}

【讨论】:

    【解决方案10】:

    如前所述,您无法可靠地确定文件是否为 Windows-1252,因为 Windows-1252 几乎将所有字节都映射到有效代码点。但是,如果文件仅在 Windows-1252 和 UTF-8 中并且没有其他编码,那么您可以尝试以 UTF-8 解析文件,如果它包含无效字节,则它是 Windows-1252 文件

    if iconv -f UTF-8 -t UTF-16 $FILE 1>/dev/null 2>&1; then
        # Conversion succeeded
        echo "$FILE is in UTF-8"
    else
        # iconv returns error if there are invalid characters in the byte stream
        echo "$FILE is in Windows-1252. Converting to UTF-8"
        iconv -f WINDOWS-1252 -t UTF-8 -o ${FILE}_utf8.txt $FILE
    fi
    

    这类似于许多其他尝试将文件视为 UTF-8 并检查是否有错误的答案。它在 99% 的时间都有效,因为大多数 Windows-1252 文本在 UTF-8 中无效,但仍然会在极少数情况下无效。毕竟是启发式的!

    还有各种库和工具可以检测字符集,比如chardet

    $ chardet utf8.txt windows1252.txt iso-8859-1.txt utf8.txt: utf-8 置信度 0.99 windows1252.txt:Windows-1252 有信心 0.73 iso-8859-1.txt:ISO-8859-1 置信度 0.73

    由于启发式的性质,它不能完全可靠,所以它输出一个置信度值供人们判断。文件中的人类文本越多,它就越有信心。如果您有非常具体的文本,则需要对图书馆进行更多培训。更多信息请阅读How do browsers determine the encoding used?

    【讨论】:

      【解决方案11】:

      找到这个documentation for the TYPE command

      将 ASCII (Windows1252) 文件转换为 Unicode (UCS-2 le) 文本文件:

      For /f "tokens=2 delims=:" %%G in ('CHCP') do Set _codepage=%%G    
      CHCP 1252 >NUL    
      CMD.EXE /D /A /C (SET/P=ÿþ)<NUL > unicode.txt 2>NUL    
      CMD.EXE /D /U /C TYPE ascii_file.txt >> unicode.txt    
      CHCP %_codepage%    
      

      上述技术(基于 Carlos M. 的脚本)首先创建一个带有字节顺序标记 (BOM) 的文件,然后附加原始文件的内容。 CHCP 用于确保会话使用 Windows1252 代码页运行,以便正确解释字符 0xFF 和 0xFE (ÿþ)。

      【讨论】:

        【解决方案12】:

        UTF-8 没有 BOM,因为它既多余又无效。 BOM 有用的地方是 UTF-16,它可以像 Microsoft 一样进行字节交换。 UTF-16 如果用于内存缓冲区中的内部表示。使用 UTF-8 进行交换。默认情况下,UTF-8、从 US-ASCII 和 UTF-16 派生的任何其他内容都是自然/网络字节顺序。 Microsoft UTF-16 需要 BOM,因为它是字节交换的。

        为了将 Windows-1252 转换为 ISO8859-15,我首先将 ISO8859-1 转换为 US-ASCII 以获取具有相似字形的代码。然后我将 Windows-1252 转换为 ISO8859-15,其他非 ISO8859-15 字形转换为多个 US-ASCII 字符。

        【讨论】:

        • 在 Windows 中,UTF-8 中的 BOM 不是 BOM 而是一种签名,因为There Ain't No Such Thing as Plain Text,你必须有办法区分各种类型的文本文件.如果文件具有 UTF-8 BOM 签名,则 Windows 将其视为 UTF-8 文件,否则为 ANSI 编码。在 Linux 中,所有文本文件仅使用 UTF-8,因此无需区分
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2012-08-16
        • 2013-09-10
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-05-06
        相关资源
        最近更新 更多