如何在文件中搜索数字
How do i search a number in a file?
每一行有一个字符串和一个数字。我已经完成了搜索函数来搜索一个名字,它工作了
例如在包含以下内容的文件中:
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:
您基本上需要执行以下操作
- 将文件加载到表示文件逻辑结构的数据结构中(例如std::map用于存储名称和编号)。这涉及到解析文件内容。你可以使用stringstream。
- 修改内存中的数据(例如data["Batman"] += 100;为与"蝙蝠侠"相关的数字添加100)
- 以请求的格式在输出文件中存储数据结构
如果输入文件必须用作输出文件,只需重新打开覆盖标志(这应该是默认的)
我修改了代码来正确处理文件,您应该能够测试它:
#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对象,然后修改内存中的数据,然后再次写入。
如果你不能使用这些(例如,如果它是一些作业,你的老师是限制你),你可能会编写自己的例程管理固定大小的记录(也许提供一些更高层次的抽象在他们之上),这可能是一些标记联合可能包含偏移到其他记录(这基本上是什么数据库系统和索引文件正在做的)。如果你被限制使用文本文件(这是个好主意;你最好有数据,你可以修改任何好的编辑器,(emacs
或vim
),然后你必须解析整个文件,存储它的表示在内存中(例如,也许一些std::map<std::string,long>
在你的情况下,键是名称),然后重写整个文件。
- 比较并显示使用最小值(a,b)和最大值(a、b)升序排列的4个数字
- 搜索字符串是否至少包含一次从 0 到 9 的所有数字的最有效方法
- 使用二叉搜索查找数字的第 N 次出现的索引
- C 搜索数组以获取一个数字,但如果找不到该数组,则不会触发其他语句
- C 搜索算法第一个数字= n
- 如何在较高和较低数字的阵列中适应搜索算法(3N / 2)-2
- 在不进行线性搜索的情况下,在非常大的数组中找到比给定数字更小的数字
- 在字符串中的一行中搜索大于0的数字
- 在字符串中搜索数字
- 使用cctype库搜索函数,以查找某个范围内的数字字符数
- 二叉搜索以查找数字所在的范围
- 在未排序的数组中搜索一个数字
- C++搜索数组中最大的数字
- 在C++中存储和搜索数字的最佳方式
- 给定一个二叉搜索树和一个数字,找到一个路径,其节点的数据被添加为给定的数字。
- 在N个未排序的数字中搜索给定值的最佳方法
- 使用指针和线性搜索在数组中找到较大和最小的数字
- 在c++中,检查一个数字是否已经添加到列表中,而不需要暴力搜索该列表
- std::string 搜索字符串中的数字并在前后插入空格
- 如何在文件中搜索数字