我如何显示以字母开头的结果,例如只显示a

How do I show results that start with a letter e.g A only

本文关键字:显示 结果 开头 何显示      更新时间:2023-10-16

我有一个list.txt文件。

它包含大约100条记录,但如果用户cin是一个字母,例如a,我只想在循环中显示所有包含a的记录。

记录是以换行格式记录的,在shell命令中我们使用A*,但在C++中,我们如何做到这一点?

示例:

Alfred
Alpha
Augustine
Bravo
Charlie
Delta

这里有很多方法,选择你更喜欢的;)


具有字符串和流的Crappy解决方案:

std::vector< std::string > vec;//this will hod the file data
std::ifstream ifs("test.txt");//the input file stream
std::string tmp;//a temporary string
while( ifs >> tmp )//reading the whole data from the file
    vec.push_back(tmp);
for( int i = 0; i < vec.size(); i++ )
    if(vec[i][0] == 'a')//vec[i][0] stands for "the first symbol of element number i in vector"
        std::cout << vec[i] << std::endl;//outputting the string if it starts with 'a'

如果您有c++11,您可以将for替换为基于以下范围的:

for( std::string & s : vec )
    if(s.at(0) == 'a')
        std::cout << s << std::endl;

或者,您可以将事情进一步复杂化,并将for替换为std::copy_if和c++11中的lambdas(IMO对于这样一个简单的场合来说,它太复杂了,很难阅读,但我仍然会将其包括在内):

//this will copy all strings starting with 'a' into res vector.
std::vector< std::string > res;
std::copy_if(vec.begin(), vec.end(), back_inserter(res), [](const std::string & s){ return s[0]=='a'; } );

如果你不需要在任何地方存储字符串,那就更容易了:

std::vector< std::string > vec;
std::ifstream ifs("test.txt");
std::string tmp;
while( ifs >> tmp )
    if( tmp.at(0) == 'a' )
        std::cout << tmp;

不使用字符串流的老式解决方案:

FILE * f = fopen("test.txt", "r");//opening the file
if( !f )//checking in case it didn't open
    return -1;
char buffer[255];//buffer for the strings being read from file
while( !feof(f) )
{
    fgets(buffer, 255, f);//getting a string
    if(buffer[0] == 'a')//printing if it starts with 'a'
        printf("%s", buffer);
}
fclose(f);//don't forget to close the file

这里有一个相当优雅、可能更惯用的解决方案:

#include <algorithm> //for copy_if
#include <cctype> //for tolower
#include <fstream> //for ifstream
#include <iostream> //for cout, cin
#include <iterator> //for istream_iterator, ostream_iterator
#include <string> //for string
int main() {
    char letter;
    std::cout << "Enter the letter to look for: ";
    std::cin >> letter; //I didn't validate it
    std::ifstream fin ("names.txt");
    std::istream_iterator<std::string> ifbegin (fin); //begin file iter
    std::istream_iterator<std::string> ifend; //end file iter
    std::ostream_iterator<std::string> obegin (std::cout, " "); //begin out iter
    std::copy_if (ifbegin, ifend, obegin, //copy from file to output if
        [letter] (const std::string &str) { //capture letter
            return std::tolower (str [0]) == std::tolower (letter);
        } //copy if starts with upper/lower case of entered letter
    );
}

请注意,copy_if和lambda确实需要C++11。这会输出文件中的每个名称,以输入的字母的大小写开始,并用空格分隔。它在对数据进行排序时执行的操作与在对数据未进行排序时相同。

正如Luc在下面指出的那样,这将读取带有空格的行的单独名称。如果你想绕过这一点,你需要一个自定义的替换operator>>读取一行。

步骤1:创建替换:

struct Line {
    std::string text; //note I made this public to save time
    operator std::string() const {return text;} //less work later
};

步骤2:修改operator>>为结构读取一行:

std::istream &operator>> (std::istream &in, Line &line) {
    std::getline (in, line.text); //get whole line
    return in;
}

步骤3:更改迭代器以使用我们的自定义结构。请注意,最后一个保留为字符串,因为它可以隐式转换为一个。让我们也用换行符来分隔打印,这样我们就可以判断它是一行,而不是一个词:

std::istream_iterator<Line> ifbegin (fin); //begin file iter
std::istream_iterator<Line> ifend; //end file iter
std::ostream_iterator<std::string> obegin (std::cout, "n"); //begin out iter

步骤4:更改lambda以满足我们的需求:

[letter] (const std::string &line) {
        return !line.empty() //we introduced the possibility of "" 
               && (std::tolower (line [0]) == std::tolower (letter));
}

4个简单的步骤后,我们完成了!

如果您确实需要新列表,我建议使用remove_copy_if;如果您不需要,则建议使用检查谓词的lambda表达式for_each。你能详细说明一下你所说的"表演"是什么意思吗?