识别字符串(是或)是否可能是 UTF-8 编码的最佳方法是什么?Win32 APIIsTextUnicode
在这里没有多大帮助。此外,该字符串不会有 UTF-8 BOM,因此无法检查。而且,是的,我知道只有 ASCII 范围以上的字符才被编码为超过 1 个字节。
9 回答
Mozilla 开发的用于 FireFox 的chardet字符集检测。源代码
jchardet是来自 mozilla 的自动字符集检测算法的源代码的 java 端口。
NCharDet是 Mozilla 和 FireFox 浏览器中使用的 C++ 的 Java 端口的 .Net (C#) 端口。
使用 Microsoft 的MLang进行字符编码检测的代码项目 C#示例。
UTRAC是用 C++ 编写的用于检测字符串编码的命令行工具和库
cpdetector是一个用于编码检测的java项目
chsdet是一个 delphi 项目,是一个独立的可执行模块,用于对给定文本或文件进行自动字符集/编码检测。
另一个有用的帖子指向很多库来帮助您确定字符编码http://fredeaker.blogspot.com/2007/01/character-encoding-detection.html
您还可以查看相关问题How Can I Best Guess the Encoding when the BOM (Byte Order Mark) is Missing? ,它有一些有用的内容。
没有真正可靠的方法,但基本上,作为字节的随机序列(例如,标准 8 位编码的字符串)不太可能是有效的 UTF-8 字符串(如果设置了字节的最高有效位,关于 UTF-8 中可以跟随什么样的字节有非常具体的规则),您可以尝试将字符串解码为 UTF-8,如果没有解码错误,则认为它是 UTF-8。
确定是否存在解码错误完全是另一个问题,许多 Unicode 库只是用问号替换无效字符,而不指示是否发生错误。因此,您需要一种明确的方法来确定解码时是否发生错误。
这个 W3C 页面有一个用于验证 UTF-8 的 perl 正则表达式
对于 Win32,您可以使用 mlang API,这是 Windows 的一部分,并且受 Windows XP 的支持,很酷的一点是,它可以为您提供输入在特定编码中的可能性的统计信息:
CComPtr<IMultiLanguage2> lang;
HRESULT hr = lang.CoCreateInstance(CLSID_CMultiLanguage, NULL, CLSCTX_INPROC_SERVER);
char* str = "abc"; // EF BB BF 61 62 63
int size = 6;
DetectEncodingInfo encodings[100];
int encodingsCount = 100;
hr = lang->DetectInputCodepage(MLDETECTCP_NONE, 0, str, &size, &encodings, &encodingsCount);
要在 ruby 中进行字符检测,请安装“chardet”gem
sudo gem install chardet
这是一个在标准输入流上运行 chardet 的小 ruby 脚本。
require "rubygems"
require 'UniversalDetector' #chardet gem
infile = $stdin.read()
p UniversalDetector::chardet(infile)
Chardet 从其统计分析中输出对字符集编码的猜测以及置信度 (0-1)
基于 Mozilla 字符集检测器的 C/C++ 独立库
https://github.com/batterseapower/libcharsetdetect
通用字符集检测器 (UCSD) 向 Mozilla C++ UCSD 库公开 C 接口和无依赖性接口的库。该库提供了一组高度准确的启发式方法,试图确定用于对某些输入文本进行编码的字符集。当您的程序必须处理没有任何编码元数据提供的输入文件时,这非常有用。
您没有指定语言,但在 PHP 中您可以使用mb_check_encoding
if(mb_check_encoding($yourDtring, 'UTF-8'))
{
//the string is UTF-8
}
else
{
//string is not UTF-8
}
在 Windows 上,您可以使用MultiByteToWideChar()
代码CP_UTF8
页和MB_ERR_INVALID_CHARS
标志。如果函数失败,则字符串不是有效的 UTF-8。
作为上一个关于 Win32 mlang DetectInputCodepage() API 的答案的附加内容,以下是如何在 C 中调用它:
#include <Mlang.h>
#include <objbase.h>
#pragma comment(lib, "ole32.lib")
HRESULT hr;
IMultiLanguage2 *pML;
char *pszBuffer;
int iSize;
DetectEncodingInfo lpInfo[10];
int iCount = sizeof(lpInfo) / sizeof(DetectEncodingInfo);
hr = CoInitialize(NULL);
hr = CoCreateInstance(&CLSID_CMultiLanguage, NULL, CLSCTX_INPROC_SERVER, &IID_IMultiLanguage2, (LPVOID *)&pML);
hr = pML->lpVtbl->DetectInputCodepage(pML, 0, 0, pszBuffer, &iSize, lpInfo, &iCount);
CoUninitialize();
但测试结果非常令人失望:
- 它无法区分 CP 437 和 CP 1252 中的法语文本,即使文本在错误的代码页中打开时完全不可读。
- 它可以检测以 CP 65001 (UTF-8) 编码的文本,但不能检测以 UTF-16 编码的文本,因此很有把握地错误地报告为 CP 1252!