作者loveme00835 (髮箍)
看板C_and_CPP
標題Re: [討論] C++ 讀取資料後如何抓取目標值?
時間Wed Oct 7 01:42:57 2020
※ 引述《forthcoming5 (XDDD)》之銘言:
: 最近自學到ifstream等寫法
: 其中有個題目是將ifstream讀出來的檔案
: 做分類+統整,檔案是.txt
: txt的內容例如:
: &@$@&&@@:((;(&
: 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()
的話會省下不少功夫 :)
--
※ 發信站: 批踢踢實業坊(ptt.cc), 來自: 61.216.75.43 (臺灣)
※ 文章網址: https://www.ptt.cc/bbs/C_and_CPP/M.1602006183.A.438.html
推 CoNsTaR: 說實話原 Po 沒有把檔案的語法講清楚根本無法實作 10/07 03:06
→ CoNsTaR: eg. Rule fixed 出現在上面的部分?多個 Rule fixed?上 10/07 03:06
→ CoNsTaR: 面的部分可以為空?... 10/07 03:06
→ CoNsTaR: 先把 syntax tree 定義好再來 parse 比較實在吧 10/07 03:06
推 ddavid: 也沒那麼無法實作吧,他也講得很清楚上面的東西全捨棄,所 10/07 09:41
→ ddavid: 以根本不用考慮上面有多少東西或可能沒有東西,一行一行讀 10/07 09:42
→ ddavid: 到某行是Rule fixed即可 10/07 09:42
※ 編輯: loveme00835 (123.193.76.216 臺灣), 10/07/2020 14:20:05
推 CoNsTaR: 要是上面可以包含 Rule fixed 你要怎麼知道哪裡屬於“上 10/07 15:32
→ CoNsTaR: 面”? 10/07 15:32
推 ddavid: 對,你當然可以追究細節跟各種例外處理 10/08 12:48
→ ddavid: 但是這跟「無法實作」完全是兩回事 10/08 12:48
→ ddavid: 業界多得是根本不知道上線才會發生什麼莫名其妙狀況的實作 10/08 12:49
→ ddavid: ,沒有人會跟你說我得要把所有可能性毫無遺漏才能「實作」 10/08 12:50
→ ddavid: 這題目的基礎要求已經很明確了,當然可以實作 10/08 12:50
→ ddavid: 只是你的實作可能會有缺陷,比如說我們都不知道原題目定義 10/08 12:51
→ ddavid: 的完整文字,所以我們並不知道會不會有兩行Rule fixed,會 10/08 12:51
→ ddavid: 不會有大小寫不同的rULE FIXED,會不會根本沒有一行是 10/08 12:52
→ ddavid: Rule fixed,會不會在Rule fixed的前中後有\r\n\t 10/08 12:52
→ ddavid: 但你還是可以先寫一個滿足已知最單純情況的實作 10/08 12:53
→ ddavid: 然後如果你想到以上那些特殊情況,可是題目沒講會不會發生 10/08 12:55
→ ddavid: 或該不該處理,那就表示我們可以無視讓它發生錯就錯,或者 10/08 12:55
→ ddavid: 用心點為每個情況寫個處理,終究都還是可以實作一個版本啊 10/08 12:56
→ ddavid: 這邊的用詞應該是「題意不夠嚴謹」而不是「無法實作」, 10/08 12:57
→ ddavid: 「無法實作」這詞我會擺在根本沒講清楚基本要幹嘛或真的做 10/08 12:57
→ ddavid: 不到的情況XD 10/08 12:58
推 lc85301: 傳說中的客戶進門點了一盤炒飯,酒吧陷入大火 10/08 20:35
推 CoNsTaR: 你當然可以寫一些自己都不知道在做什麼的程式去搪塞,但 10/08 22:46
→ CoNsTaR: 對我來說那不叫實作 10/08 22:46