更簡單和更快速的解析代碼:使用 std::views::split
解析文本文件在任何編程語言中通常都是一件棘手的事情,並且速度往往令人驚訝地慢。
以下是一個例子。假設你有一個用逗號分隔的值(CSV)文件。這是一個由多行組成的文本文件,每行根據逗號分隔成不同的字段。Excel 試算表經常以 CSV 文件的形式導出。你想提取其中的一列並對其進行迭代。
我請求 ChatGPT 提供一個 C++ 的解決方案,並得到了以下代碼:
“`cpp
std::vector get_column(const std::string& input,
size_t row_number, char delimiter = ‘,’) {
std::vector rows;
std::istringstream iss(input);
std::string row;
// 將字符串分割成行
while (std::getline(iss, row)) {
rows.push_back(row);
}
std::vector result;
for (const auto& r : rows) {
std::istringstream row_stream(r);
std::string field;
size_t index = 0;
while (std::getline(row_stream, field, delimiter)) {
if (index == row_number) {
result.push_back(field);
break;
}
++index;
}
}
return result;
}
“`
這個函數接受一個字符串作為 CSV 類數據的輸入、一個列索引 row_number,以及一個可選的分隔符(默認為逗號)。它將輸入字符串分割成行,然後對每一行進一步根據分隔符分割成字段。它從每一行中收集指定列索引的字段,並將其返回為字符串向量。
這段代碼很糟糕。我不認為任何專業的 C++ 程序員會寫出如此拙劣的代碼。不過,我也可能會被驚訝。
如果你擁有一個現代的 C++20 系統,可以用更少的代碼寫出高效的代碼,使用 std::views::split。讓我來演示一下:
“`cpp
auto get_column_cxx20(std::string_view data,
size_t row_number, char delimiter = ‘,’) {
auto rows = data | std::views::split(‘n’);
auto column =
rows |
std::views::transform(
[delimiter, row_number](auto &&row) {
auto fields = row | std::views::split(delimiter);
auto it = std::ranges::begin(fields);
std::advance(it, row_number);
return *it;
}) |
std::views::transform([](auto &&rng) -> std::string_view {
return std::string_view(&*rng.begin(),
std::ranges::distance(rng));
});
return column;
}
“`
這個函數利用 C++20 的範圍和視圖來提取表示為 std::string_view 的 CSV 類數據中特定的列。它首先使用換行符將輸入數據分割成行,然後進行一系列轉換:根據分隔符將每行分割成字段,選擇指定列索引(row_number)中的字段,最後將這些選定的字段轉換回 std::string_view 對象。這種方法在內存使用上非常高效,因為它避免了數據複製,並使用惰性評估僅在必要時處理數據。
我寫了一個小基準,使用一個現有的 CSV 文件,要求提取第二列並計算該列的寬度。使用 LLVM 16 和 Apple M2 處理器,我得到了以下結果:
舊方法:0.11 GB/s
std::views::split:2.6 GB/s
重要的是,這裡沒有磁碟訪問。所有操作都在內存中。因此,舊方法的性能僅為可憐的 0.11 GB/s。我的源代碼可在 GitHub 上找到。
我並沒有嘗試對 std::views::split 方法進行調優。我懷疑我們可以通過進一步調整來獲得更好的性能。不過,它已經比簡單的方法快了 20 倍。
使用 std::views::split 進行字符串操作的主要麻煩在於,它自然地與範圍和子範圍一起工作,而我更喜歡使用 std::string_view 實例。因此,我們看到代碼中有一個笨拙的轉換例程。我尚未找到簡化這部分代碼的方法。
在這篇文章中,Daniel Lemire 提出了使用 C++20 的新特性來優化 CSV 解析的思路,這不僅提高了性能,也簡化了代碼結構。隨著數據處理需求的增加,這種方法的效率無疑會吸引越來越多的開發者去探索和實施。未來,隨著 C++ 的進一步發展,我們可能會看到更多這類創新,幫助開發者在日常工作中提高效率,減少冗餘的代碼。
以上文章由特價GPT API KEY所翻譯及撰寫。而圖片則由FLUX根據內容自動生成。