如何在文件中搜索数字

How do i search a number in a file?

本文关键字:搜索 数字 文件      更新时间:2023-10-16

每一行有一个字符串和一个数字。我已经完成了搜索函数来搜索一个名字,它工作了

例如在包含以下内容的文件中:

Batman 290
Joker 100
Spiderman 300

但是我现在面临的问题是如何修改字符串旁边的数字。例如,当我搜索"蝙蝠侠"这个名字时,我只想更改蝙蝠侠的号码。

下面是添加的代码:
void Teacher::addScore(string name, double score) {
    outStream.open("StudentRecord.txt", ios_base::app);
    outStream << name << " || " << score << endl;
    outStream.close();
}

查找

string Teacher::search(string searchKeyword) {
    int count = 0;
    string name;
    readStream.open("StudentRecord.txt");
    while (readStream.is_open()) {
        getline(cin, name);
        while (readStream >> name) {
            if(name == searchKeyword) {
                count++;
                return name;
            }
        }
        if(name != searchKeyword) {
            return "That student doesnt exist";
        }
    }
    return "";
}

对于修改,我在这个阶段遇到了麻烦

void Teacher::modifyScore() {
    string name;
    string searchResult;
    cout << "You want to modify the a student score?" << endl;
    cout << "Which student's you want to change?" << endl;
    cin >> name;
    searchResult = search(name);
    outStream.open("StudentRecord.txt", ios::trunc);
    // What should I do here to modify a student number?  
}

第二次编辑:带有读写代码

请注意,代码不是最优的,并且没有任何错误检查。数据假定在"data.txt"中。

#include <fstream>
#include <iostream>
#include <string>
#include <sstream>
#include <map>
int main()
{
    // Holds file data
    std::map<std::string, int> data;
    // Read file and fill data map
    std::ifstream ifs("data.txt");
    std::string line;
    while (std::getline(ifs, line))
    {
        std::string name;
        int number;
        std::stringstream ss(line);
        ss >> name >> number;
        data[name] = number;
    }
    ifs.close();
    // Print data
    for (auto& entry : data)
    {
        std::cout << entry.first << " " << entry.second << std::endl;
    }
    // Modify data
    data["Batman"] += 100;
    // Open same file for output, overwrite existing data
    std::ofstream ofs("data.txt");
    for (auto& entry : data)
    {
        ofs << entry.first << " " << entry.second << std::endl;
    }
    ofs.close();
    return 0;
}

Edit:原始答案假设文件结构已知(每行字符串和编号)

要在文件中查找数字,需要将文件内容解析为所谓的"令牌"。示例:字符串"foo 10 0.1"将被分解为"foo","10","0.1",使用空白字符作为分隔符。这个过程被称为标记化。接下来,您需要检查每个标记是否代表一个有效的数字,要这样做,只需检查每个字符是否为一个有效的整数。

原始amswer:

您基本上需要执行以下操作

  1. 将文件加载到表示文件逻辑结构的数据结构中(例如std::map用于存储名称和编号)。这涉及到解析文件内容。你可以使用stringstream。
  2. 修改内存中的数据(例如data["Batman"] += 100;为与"蝙蝠侠"相关的数字添加100)
  3. 以请求的格式在输出文件中存储数据结构

如果输入文件必须用作输出文件,只需重新打开覆盖标志(这应该是默认的)

我修改了代码来正确处理文件,您应该能够测试它:

#include "stdafx.h" // for VC++
#include <iostream>
#include <fstream>
#include <string>
#define score_file "d:\StudentRecord.txt"
#define score_file_bak score_file".bak"
#define score_file_new score_file".new"

using namespace std;
void addScore(string name, double score) 
{
    ofstream outStream;
    outStream.open(score_file, ios_base::app);
    outStream << name << "||" << score << endl;
    outStream.close();
}

void modifyScore(string name, double score) {
    string line;
    int fd =0;
    ifstream scores(score_file);
    if(!scores.is_open()){
        std::cout << "Unable to read score file" << std::endl;
        return ;
    }
    ofstream outStream(score_file_new);
    if(!outStream.is_open()){ 
        std::cout << "Unable to open temp file to write" << std::endl;
        return ;
    }
    name += "||";
    while(getline(scores, line)){
        if(line.find(name) == 0){
            std::cout << "Found: " << line << std::endl;
            outStream << name << score << std::endl;
            fd++;
        }
        else{
            outStream << line << std::endl;
        }
    }
    scores.close();
    outStream.close();
    if(fd<1){ 
        remove(score_file_new);
        std::cout << "Not found: " << name << std::endl;
    }
    else{
        remove(score_file_bak);// delete previous backup
        if(0 != rename(score_file,score_file_bak)){
            std::cout << "Unable to backup" << std::endl;
            remove(score_file_new);  // delete the new file since update failed
            return;
        }
        if(0 == rename(score_file_new,score_file)) 
            std::cout << "Updated succeeded." << std::endl;
        else
            std::cout << "Unable to updaten" << std::endl;
    }
}
void showScore()
{
    string line;
    ifstream scores(score_file);
    while(getline(scores, line)){
        cout << line << std::endl;
    }
    scores.close();
}
int main()
{
    bool reset_scores = true; //do you want to reset all scores?
    if(reset_scores) // clean all old records?  
    {
        ofstream outStream(score_file, ios_base::trunc);outStream.close();
        addScore("Tom",120); addScore("Jerry", 130); addScore("Tim",100);
    }
    std::cout << "Here are the scores" << std::endl;
    showScore();
    std::cout << "Try to change Timmy's score:" << std::endl;
    modifyScore("Timmy",200);
    showScore();
    std::cout << "Try to change Jerry's score:" << std::endl;
    modifyScore("Jerry",1190);
    showScore();
    if(1)
    {
        string aaa; 
        std::cout << "Press enter to quit:n";
        getline(cin, aaa);
    }
    return 0;
}

我有这样的输出:

 Here are the scores
 Tom||120
 Jerry||130
 Tim||100
 Try to change Timmy's score:
 Not found: Timmy||
 Tom||120
 Jerry||130
 Tim||100
 Try to change Jerry's score:
 Found: Jerry||130
 Updated succeeded.
 Tom||120
 Jerry||1190
 Tim||100
 Press enter to quit:

你需要学会如何自己处理输入。

你不能修改文件"in their middle";也就是说,您只能截断或追加到文件中,或者用另一个字节序列(具有相同长度)覆盖字节序列。

因此,正如RedAgito的回答所建议的那样,您可以在内存中读取整个文件,修改内存中的表示,然后重写整个文件。

当然,这种方法的可扩展性不是很好(但实际上是值得的:笔记本电脑有千兆字节的RAM,一个千兆字节的文本文件将包含数百万行名称-数字行,这通常是足够的):单个修改的复杂性与行数成正比(除非你知道所有的数字都是相同的宽度-例如一些电话号码;然后您可以覆盖该行,但您仍然需要找到匹配的行)。

一个实用的方法可能是使用一些数据库(可能像sqlite库一样简单;或全功能的DBMS,如PostGreSQL或MongoDB),或一些索引文件库(如GDBM或kyotocabinet)。

另一种方法可能是使用一些传统的文本结构化格式,如JSON或YAML(或者可能是XML,它不太适合您的任务)。有许多c++库可以轻松处理这种格式(例如jsoncpp和许多其他库)。然后,您将解析整个文件(在几个c++语句中),可能作为单个(但很大的)JSON对象,然后修改内存中的数据,然后再次写入。

如果你不能使用这些(例如,如果它是一些作业,你的老师是限制你),你可能会编写自己的例程管理固定大小的记录(也许提供一些更高层次的抽象在他们之上),这可能是一些标记联合可能包含偏移到其他记录(这基本上是什么数据库系统和索引文件正在做的)。如果你被限制使用文本文件(这是个好主意;你最好有数据,你可以修改任何好的编辑器,(emacsvim),然后你必须解析整个文件,存储它的表示在内存中(例如,也许一些std::map<std::string,long>在你的情况下,键是名称),然后重写整个文件。