2021年5月19日 星期三

C/C++ 依照特定格式 讀取檔案並 切割字串

C/C++ 依照特定格式 讀取檔案並 切割字串

tags: 部落格文章

這個新手大概很常用到,每次要用都google半天。這篇是把這些常用的函式封裝成一個物件,直接解決痛點方便操作。

因為是用 C++ 17 寫的,刷題提交用的代碼可能用不上,網站未必支援。簡單的讀檔可以參考這邊兩篇站內文。

讀取檔案

讀檔的問題參照上面兩篇就可以解決,這邊就概略貼上代碼就好

// 逐行讀取
vector<string> ReadFile_line(const string file_name) {
    vector<string> v;
    fstream fs(file_name, ios::in);
    if (!fs.is_open())
        throw runtime_error("Reading error.");
    for (string str; getline(fs, str);)
        v.emplace_back(str);
    return v;
}



切割字串

傳統的C字串處理可以這樣寫

#include <string.h>
void stringSplit(char* str, const char* delim) {
    char temp[64];
    strcpy(temp, str);

    char* pch = strtok(temp, delim);
    while (pch != NULL) {
        printf("%s\n", pch);
        pch = strtok(NULL, delim);
    }
}

C++ 11 可以這樣寫

#include <string>
void split(const string& s, vector<string>& tokens,
    const string& delimiters = " ")
{
    string::size_type lastPos = s.find_first_not_of(delimiters, 0);
    string::size_type pos = s.find_first_of(delimiters, lastPos);
    while (string::npos != pos || string::npos != lastPos) {
        tokens.push_back(s.substr(lastPos, pos - lastPos));
        lastPos = s.find_first_not_of(delimiters, pos);
        pos = s.find_first_of(delimiters, lastPos);
    }
}

C++17 可以更有效率的這樣寫

#include <string_view>
vector<string_view> splitSV(string_view strv, string_view delims = " ") {
    vector<string_view> output;
    for (size_t first = 0; first < strv.size();) {
        const auto second = strv.find_first_of(delims, first);
        if (first != second)
            output.emplace_back(strv.substr(first, second - first));
        if (second == string_view::npos)
            break;
        first = second + 1;
    }
    return output;
}

透過這樣的方式,就能夠把字串依照特定格式給切出來了。



封裝物件

切割完畢之後就用封裝拉,一般就是用 vector<string> 封裝,想要效率更高一點可以使用 vector<string_view>

因為有點長就貼到gist上了

封裝好的物件怎麼使用有一併寫在檔案底下的test函式裡

下面就簡單說明一下,最簡單的切割

string str = "123 | 321";
OneLine line(str, " | ");
cout << line << endl;

vector<string_view>&& tokenList = line;
for (size_t i = 0; i < tokenList.size(); i++)
    cout << tokenList[i] << endl;

物件本身返回的是一個 vector
這就意味了著在for裡面可以透過 line[idx] 來讀取被切割的字串

如果要從檔案讀取可以使用 openFile()

OneLine line;
line.openFile("a.txt");
while (line.getline()) {
    vector<string_view>&& tokenList = line;
    cout << tokenList << endl;
}

此時獲取的 tokenList 就可以用下標取出個別的字串了。



參考

沒有留言:

張貼留言