如何在 c++ 中读取不包含在 ascii 中的字符?

Posted

技术标签:

【中文标题】如何在 c++ 中读取不包含在 ascii 中的字符?【英文标题】:How to read a character not included in ascii in c++? 【发布时间】:2015-12-21 02:13:54 【问题描述】:

我正在浏览一个包含编辑标题的文件的文件夹。我正在尝试删除标题的某个部分,但用于分隔标题的括号不是标准的 ascii,因此我无法找到删除它的方法。这是标题的示例:【删除此部分】保留此部分。我已经包含了我正在使用的编码。我使用 cstring 来存储标题,然后使用 cstring::find() 来定位该部分,但它无法找到那种类型的括号。

    //sets definition
    HANDLE hfind;
    WIN32_FIND_DATA data;

    //creates string for to search for a specific file
    CString FileFormat = FolderPath + Format;
    CString NewTitle, PulledFile;

    //sets definition for retrieving first file
    hfind = FindFirstFile(FileFormat, &data);

    //runs loop if handle is good
    if (hfind != INVALID_HANDLE_VALUE)
    
    //loops until it hits the end of the folder
    do 
        //adds filename to vector
        PulledFile = data.cFileName;
        if(PulledFile.Find(L'【') != -1)
        
            while (PulledFile.Find(L'】') != -1)
            
                PulledFile = PulledFile.Right(PulledFile.GetLength() - 1);
            
        
        NewTitle = PulledFile.Left(PulledFile.GetLength()-(Format.GetLength() + 9));
        if (sizeof(NewTitle) != NULL)
        
            v.push_back(NewTitle);
        
     while (FindNextFile(hfind, &data));
    

【问题讨论】:

if (sizeof(NewTitle) != NULL) 非常非常错误。你想用这个比较做什么? 应该是NewTitle.GetLength() 而不是sizeof(NewTitle) 这部分没有任何意义:NewTitle = PulledFile.Left(PulledFile.GetLength() - (Format.GetLength() + 9)); 它将NewTitle 设置为NUL。这不是 Unicode 问题。 @IInspectable 他不是在读取文件本身,而是在获取以两种格式(宽字符串或 Unicode)之一返回的文件名。假设您编译正确,文件内部使用的任何编码都不会阻止您执行 OP 尝试执行的操作。 @meneldal:完全错过了,你是对的。除了,您可能想说“MBCS 或 Unicode 编码” @IInspectable MBCS 是某种邪恶,无论如何我都不想涉足。最好只知道它存在并尽可能避免它。 【参考方案1】:

您面临的最有可能的问题是编译不正确。根据CString documentation:

CStringW 对象包含wchar_t 类型并支持 Unicode 字符串。 CStringA 对象包含 char 类型,并支持单字节和多字节 (MBCS) 字符串。 CString 对象支持 char 类型或 wchar_t 类型,具体取决于在编译时是否定义了 MBCS 符号或 UNICODE 符号。

实际的底层类型取决于您的编译参数。最有可能发生的情况是它试图将 Unicode 字符串与您的 MBCS 字符串文字值进行比较,并且不返回任何内容。

如果你想解决这个问题,你应该决定是使用 Unicode 还是 MBCS,并相应地更新你的编译参数,定义 MBCSUNICODE

如果您使用 Unicode,则必须更改字符串文字,因为它目前适用于 MBCS。您可以使用代码点 L'\u3010' 来返回正确的字符,或者确保您的文件使用 Unicode 编码并使用 u'【'

【讨论】:

发布的代码必须已经为 Unicode 编译,因为它调用CString::Find(L'【')。定义为L'X' 的字符文字属于wchar_t 类型,并且CStringA 没有采用wchar_t 参数的Find 重载。因此,为了使代码完全编译,CString 必须是 CStringW,即定义了 UNICODE 的 Unicode 编译。 @dxiv 感谢您的评论我已经更新了我的答案,现在应该很好了。 感谢您的帮助。我不知道使用 mbcs 和 Unicode 的区别。【参考方案2】:

您的编辑器很可能没有将硬编码的【和】正确编码为您寻找的 unicode 字符。 Visual Studio 有时会通过将源文件自动编码为 UTF8 来实现这一点,但这并不总是可靠的,并且可能无法在需要 ascii 的源代码控制系统中生存。

最简单的做法是使用 \uNNNN 语法来匹配字符。

    if(PulledFile.Find(L'\u3010') != -1)
    
        while (PulledFile.Find(L'\u3011') != -1)
        
            PulledFile = PulledFile.Right(PulledFile.GetLength() - 1);
        
    

其中\u3010\u3011分别是【和】的unicode值的十六进制转义序列。

【讨论】:

我相信像 \x3010 这样带有 4 十六进制数字的转义是 MS 扩展。更标准的'\u3010''\u3011' 应该也可以。 它可能仍然会因为 UTF-8/宽字符比较而失败。如果您使用 ASCII 以外的字符,VS 会要求您更改编码,所以我认为这不是问题。 @dxiv - 谢谢。答案固定。 @meneldal - 这是我的期望。但是当我在 VS2015 中使用 const wchar_t* psz = L"【Title】"; 作为测试字符串运行本地测试时,Visual Studio 没有 提示或自动编码源。它将它保留为 ascii 并将括号字符视为文字 '?' (0x3f)。我必须明确将源代码保存为 UTF8 才能使其正常工作。因此,我的建议。我以为他已经在构建 Unicode,因为他在代码中使用了宽字符文字 L'【' @dxiv - 哎呀。谢谢。

以上是关于如何在 c++ 中读取不包含在 ascii 中的字符?的主要内容,如果未能解决你的问题,请参考以下文章

将十六进制转换为从文件 C++ 读取的 ASCII 的正确方法

我可以在 C++ 中读取 Windows 中的文件而不锁定包含该文件的文件夹吗

如何在 C++ 中监视一个目录并读取该目录中的图像

在 C++ 中读取文本文件中的数字和字母

C++中数字转ascii码函数

C++ 混乱。从文本文件中读取整数。转换为 ASCII