我要从文本文件中读取单词。 Word被定义为连续的字母序列。例如,在以下字符串中:
“这是一个很好的#”想法,你知道吗?“
这些词是:
这是你知道的线条的好主意
('它'和'a'加倍)
我想知道,如果有任何聪明的功能可以读取单词,直到找到一个非字母字符?或者唯一的方法是通过char读取char并使用push_back直到找到非字母的?
答案 0 :(得分:0)
当您从流中读取字符串时,该流将连续的非空白字符作为字符串读取。然后它会忽略任何空白字符。下一个非空格字符是它读取的下一个字符串的开头。这几乎就是你想要的行为,还有一个例外:你希望除了字母以外的所有东西都被视为白色空间。
幸运的是,该流并没有硬编码其对白色空间"白色空间"的想法。它使用区域设置来告诉它什么是空白区域。反过来,语言环境由处理本地化的各个方面("方面")的部分组成。专门处理字符分类的方面是ctype
方面。因此,如果我们编写一个ctype facet,将除字母以外的所有内容分类为空格,我们可以阅读" words"从流中很容易。
这里有一些代码可以做到这一点:
struct alpha_only: std::ctype<char> {
alpha_only(): std::ctype<char>(get_table()) {}
static std::ctype_base::mask const* get_table() {
static std::vector<std::ctype_base::mask>
rc(std::ctype<char>::table_size,std::ctype_base::space);
std::fill(&rc['a'], &rc['z'], std::ctype_base::lower);
std::fill(&rc['A'], &rc['Z'], std::ctype_base::upper);
return &rc[0];
}
};
ctype facet的char
特化是(总是)表驱动的。我们真正需要做的就是创建一个能够正确分类字符的表。在这种情况下,这意味着字母字符被分类为大写或小写,其他所有内容都被分类为空白。我们通过填充表ctype_base::space
来做到这一点,然后对于按字母顺序排列的字符基本上说:&#34; oops,不是那些不是空格的,那是大写还是小写
从技术上讲,我所做的方式略有不正确 - 它假设大写和小写字母是连续的。这对于任何理智的字符集都是如此,但对于EBCDIC则不然。如果我们想在技术上正确,而不是两个&#34; std :: fill&#34;调用,我们可以写一个这样的循环:
auto max = std::numeric_limits<unsigned char>::max();
for (int i=0; i<max; i++)
if (islower(i))
table[i] = std::ctype_base::lower;
else if (isupper(i))
table[i] = std::ctype_base::upper;
else
table[i] = std::ctype_base::space;
无论哪种方式,结论都相当简单:大写为大写,小写为小写,其他一切为&#34;空格&#34;。
一旦我们写完了,我们需要告诉流使用该语言环境;那么我们可以很容易地阅读我们的文字:
int main() {
std::istringstream infile("It’s a ver5y good #” idea of a line. You know it?");
// Tell the stream to use our character classifier:
infile.imbue(std::locale(std::locale(), new alpha_only));
std::string word;
while (infile >> word)
std::cout << word << "\n";
}
[我在每个&#34;单词&#34;之间添加了新的界限。所以你可以很容易地看到它作为一个单词阅读的内容。]
结果:
It
s
a
ver
y
good
idea
of
a
line
You
know
it
根据您在问题中的结果,您显然也只希望每个单词在输出中出现一次。为此,您通常会将一个单词中的每个单词作为其读取插入,并且只有在集合中插入成功时才将其写入输出。
std::unordered_set<std::string> words;
std::string word;
while (infile >> word)
if (words.insert(word).second)
std::cout << word << "\n";
insert
和set
的{{1}}返回unordered_set
,其中pair<iterator, bool>
表示插入是否成功。如果它以前存在,那将失败并返回false,所以基于此我们决定是否写出单词。
通过此修改,bool
仍然会在输出中出现两次 - 第一个实例的it
大写,第二个实例没有。{1}}。要对其进行过滤,在将每个字符串插入集合之前,您需要将每个字符串完全转换为小写字母(或完全转换为大写字母)。