令牌化

在執行時從最便宜到最昂貴的列表:

  1. str::strtok 是最便宜的標準提供的標記化方法,它還允許在標記之間修改分隔符,但它在現代 C++中遇到 3 個困難:

    • std::strtok 不能同時用於多個 strings(雖然有些實現擴充套件到支援這個,例如: strtok_s
    • 出於同樣的原因,std::strtok 不能同時在多個執行緒上使用(但是這可能是實現定義的,例如: Visual Studio 的實現是執行緒安全的
    • 呼叫 std::strtok 會修改它正在執行的 std::string,所以它不能用於 const strings,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);

例項

  1. 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>());

例項

  1. 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 示例