Re: [讨论] C++ 读取资料后如何抓取目标值?

楼主: loveme00835 (发箍)   2020-10-07 01:42:57
※ 引述《forthcoming5 (XDDD)》之铭言:
: 最近自学到ifstream等写法
: 其中有个题目是将ifstream读出来的档案
: 做分类+统整,档案是.txt
: txt的内容例如:
: &@[email protected]&&@@:((;(&
: sh tree f m hi tm it e iuytre
: Rule fixed
: 100 21
: 200 38
: 300 37
: 400 35
: 500 11
: 如果在rule跟fixed前面的文字、资料不想要
: 直接取下面的Rule跟fixed及后面的数值做处理
: 应该要怎么做呢?
: 老师是有提示用vector搭配parser等作法
: 但想很久一直没办法
: 跪求解答,将送上300p币,感恩
你可以想像 i(f)stream 是由一连串的字符所组成, 要在里面找寻特定字串可
以用 <algorithm> 里的 std::search() 来完成, 只是它要求参数必须满足
ForwardIteartor 概念 (concept), 亦即它预期迭代器 (iterator) 在没有做
累加时, 多次读出来的字符必须相同; 但 istream 物件的特性却是: 没有做快
取的情况下, 每个字符只能读一次, 是 InputRange 的概念. 当我们配对到字
串的同时, 我们也丢掉它了. 即使如此, 我们还是可以仿照 std::search() 的
逻辑顺势实作接受 InputIterator 的函式 drop_until().
drop_until() 的架构是这样的: 本体里包含一个循环, 每次迭代都只对参数做
一次累加还有读值, 并且复制读出来的物件往后做参考:
template <typename InputIterator, typename InputSentinel>
void drop_until(InputIterator first, InputSentinel last) {
while (first != last) {
auto element = *first++;
// do things here
}
}
接着我们再加入额外的参数 pattern 作为要查找的对象, 它是一种 ForwardR-
ange, 到这里和 std::search() 还蛮像的 (为了能在配对失败时重来, 我们再
新增一个迭代器物件):
template <
typename InputIterator, typename InputSentinel,
typename ForwardRange
>
void drop_until(InputIterator first, InputSentinel last,
const ForwardRange& pattern) {
// match from beginning
auto next_to_match = pattern.begin();
while (first != last && next_to_match != pattern.end()) {
auto element = *first++;
// match succeeding element in next iteration
if (element == *next_to_match) {
++next_to_match;
// fail to match, start over from second element
} else if (element == *pattern.begin()) {
next_to_match = std::next(pattern.begin());
// fail to match, start over from first element
} else {
next_to_match = pattern.begin();
}
}
}
以上还只是简单的实作, 虽然没办法处理复杂的字串, 但用来解原 po 的问题
已经足够. 有了 drop_until() 函式, 读档程式码就可以这样写:
std::ifstream file("input.txt");
drop_until(
std::istreambuf_iterator<char>(file),
std::istreambuf_iterator<char>(),
"Rule fixed\n"sv
);
unsigned rule, fixed;
while (file >> rule >> fixed) {
// do things here
}
完整范例: https://wandbox.org/permlink/gAssdOddYQtopotV
不过如果你有办法把整个档案都读进来变成一个大字串, 搭配 std::search()
的话会省下不少功夫 :)
作者: CoNsTaR ((const *))   2020-10-07 03:06:00
说实话原 Po 没有把档案的语法讲清楚根本无法实作eg. Rule fixed 出现在上面的部分?多个 Rule fixed?上面的部分可以为空?...先把 syntax tree 定义好再来 parse 比较实在吧
作者: ddavid (谎言接线生)   2020-10-07 09:41:00
也没那么无法实作吧,他也讲得很清楚上面的东西全舍弃,所以根本不用考虑上面有多少东西或可能没有东西,一行一行读到某行是Rule fixed即可
作者: CoNsTaR ((const *))   2020-10-07 15:32:00
要是上面可以包含 Rule fixed 你要怎么知道哪里属于“上面”?
作者: ddavid (谎言接线生)   2020-10-08 12:48:00
对,你当然可以追究细节跟各种例外处理但是这跟“无法实作”完全是两回事业界多得是根本不知道上线才会发生什么莫名其妙状况的实作,没有人会跟你说我得要把所有可能性毫无遗漏才能“实作”这题目的基础要求已经很明确了,当然可以实作只是你的实作可能会有缺陷,比如说我们都不知道原题目定义的完整文字,所以我们并不知道会不会有两行Rule fixed,会不会有大小写不同的rULE FIXED,会不会根本没有一行是Rule fixed,会不会在Rule fixed的前中后有\r\n\t但你还是可以先写一个满足已知最单纯情况的实作然后如果你想到以上那些特殊情况,可是题目没讲会不会发生或该不该处理,那就表示我们可以无视让它发生错就错,或者用心点为每个情况写个处理,终究都还是可以实作一个版本啊这边的用词应该是“题意不够严谨”而不是“无法实作”,“无法实作”这词我会摆在根本没讲清楚基本要干嘛或真的做不到的情况XD
作者: lc85301 (pomelocandy)   2020-10-08 20:35:00
传说中的客户进门点了一盘炒饭,酒吧陷入大火
作者: CoNsTaR ((const *))   2020-10-08 22:46:00
你当然可以写一些自己都不知道在做什么的程式去搪塞,但对我来说那不叫实作

Links booklink

Contact Us: admin [ a t ] ucptt.com