令牌化
在執行時從最便宜到最昂貴的列表:
-
str::strtok
是最便宜的標準提供的標記化方法,它還允許在標記之間修改分隔符,但它在現代 C++中遇到 3 個困難:std::strtok
不能同時用於多個strings
(雖然有些實現擴充套件到支援這個,例如:strtok_s
)- 出於同樣的原因,
std::strtok
不能同時在多個執行緒上使用(但是這可能是實現定義的,例如: Visual Studio 的實現是執行緒安全的 ) - 呼叫
std::strtok
會修改它正在執行的std::string
,所以它不能用於const string
s,const char*
s 或文字字串,用std::strtok
標記任何這些,或者操作需要保留內容的std::string
,輸入必須是複製,然後可以操作副本
通常,這些選項中的任何一個都會隱藏在令牌的分配成本中,但是如果需要最便宜的演算法並且
std::strtok
的難度不會過度,則考慮手動解決方案 。
// String to tokenize
std::string str{ "The quick brown fox" };
// Vector to store tokens
vector<std::string> tokens;
for (auto i = strtok(&str[0], " "); i != NULL; i = strtok(NULL, " "))
tokens.push_back(i);
std::istream_iterator
迭代地使用流的提取運算子。如果輸入std::string
是以空格分隔的,則可以通過消除其困難來擴充套件std::strtok
選項,允許內聯標記化從而支援const vector<string>
的生成,並通過新增對多個分隔空白字元的支援:
// String to tokenize
const std::string str("The quick \tbrown \nfox");
std::istringstream is(str);
// Vector to store tokens
const std::vector<std::string> tokens = std::vector<std::string>(
std::istream_iterator<std::string>(is),
std::istream_iterator<std::string>());
std::regex_token_iterator
使用std::regex
進行迭代標記。它提供了更靈活的分隔符定義。例如,非分隔逗號和空格:
Version >= C++ 11
// String to tokenize
const std::string str{ "The ,qu\\,ick ,\tbrown, fox" };
const std::regex re{ "\\s*((?:[^\\\\,]|\\\\.)*?)\\s*(?:,|$)" };
// Vector to store tokens
const std::vector<std::string> tokens{
std::sregex_token_iterator(str.begin(), str.end(), re, 1),
std::sregex_token_iterator()
};
有關詳細資訊,請參閱 regex_token_iterator
示例 。