为什么我不能在没有崩溃的情况下使用ifstream读取撇号?

时间:2017-11-25 20:05:10

标签: c++ visual-studio c++11

我正在使用此代码:

std::string word;
std::ifstream f((file_name + ".txt").c_str());
while (f >> word) {
    good_input = true;
    for (int i = 0; i < word.length(); ++i) {
        if (ispunct(word.at(i))) {
            word.erase(i--, 1);
        }
        else if (isupper(word.at(i))){
            word.at(i) = tolower(word.at(i));
        }
    }

每次我读到&#34;没有&#t;#34;从文本文件中,我收到此错误:

  

Debug Assertion失败!
  程序:目录 \ SortingWords(长度).exe
  文件:minkernel \ crts \ ucrt \ src \ appcrt \ convert \ istype.cpp
  行:36
  表达式:c> = -1&amp;&amp; c&lt; = 255
  有关更多信息,请访问... [等]

当我点击&#34; abort&#34;时,我的程序会以代码3退出。不知道这有用吗?

看起来它可能与撇号有关?此代码可以找到我的文档中的所有其他单词,直到这个。并且适用于不包含撇号的文档,但它们包含大量其他标点符号...

我尝试更改文本文件的编码(简单地用记事本制作),但这没有用。一般都会发现很多关于撇号的抱怨,但没有合适的答案。谁能帮我弄清楚发生了什么?

1 个答案:

答案 0 :(得分:0)

正如documentation for ispunct所说:

  

如果ch的值不能表示为,则行为未定义   unsigned char并且不等于EOF

如果链接到调试运行时,Visual C ++足以为此错误添加几乎显式的消息(这通常是未定义行为的情况 - 使用发布运行时,它只是崩溃或行为奇怪;使用调试运行时,你得到一个错误对话框)。

理论上,这意味着在您的环境使用的字符集中,'无法表示为unsigned char,即其字符代码太大或太低。

在实践中,这似乎不太可能,甚至可能在Windows上无法实现。您的文件更可能不包含撇号,但只有看起来像的字符,例如重音:´

以下是如何以简单的方式重现问题:

#include <ctype.h>

int main()
{
    ispunct('\'');
    ispunct('´'); // undefined behaviour (crash or error message with Visual C++)
}

isupper也有同样的问题。

您可以使用static_cast安全地使用这些功能,例如:

if (ispunct(static_cast<unsigned char>(word.at(i))))

当然,现在ispunct将为角色返回零。如果你真的需要覆盖´,你必须明确地这样做,例如使用这样的辅助函数:

bool extended_ispunct(int c)
{
    return static_cast<unsigned char>(c) || c == '´';
}