Для тех, кому не очень удобно жертвовать всей эффективностью ради размера кода и рассматривать «работоспособность» как тип элегантности, следующее должно быть приятно: (и я думаю, что класс контейнера шаблонов является удивительно элегантным дополнением .):
template < class ContainerT >
void tokenize(const std::string& str, ContainerT& tokens,
const std::string& delimiters = " ", bool trimEmpty = false)
{
std::string::size_type pos, lastPos = 0, length = str.length();
using value_type = typename ContainerT::value_type;
using size_type = typename ContainerT::size_type;
while(lastPos < length + 1)
{
pos = str.find_first_of(delimiters, lastPos);
if(pos == std::string::npos)
{
pos = length;
}
if(pos != lastPos || !trimEmpty)
tokens.push_back(value_type(str.data()+lastPos,
(size_type)pos-lastPos ));
lastPos = pos + 1;
}
}
Обычно я выбираю std::vector<std::string>
типы в качестве второго параметра (ContainerT
) ... но list<>
намного быстрее, чем vector<>
, когда прямой доступ не требуется, и вы даже можете создать свой собственный Строка класса и использовать что-то вроде std::list<subString>
, где subString
не делает никаких копий для невероятного увеличения скорости.
Это более чем в два раза быстрее, чем самый быстрый токен на этой странице, и почти в 5 раз быстрее, чем некоторые другие. Также с идеальными типами параметров вы можете исключить все копии строк и списков для дополнительного увеличения скорости.
Кроме того, он не выполняет (крайне неэффективный) возврат результата, а скорее передает токены в качестве ссылки, что также позволяет вам создавать токены, используя несколько вызовов, если вы того пожелаете.
Наконец, он позволяет указать, следует ли обрезать пустые токены из результатов с помощью последнего необязательного параметра.
Все, что ему нужно, это std::string
... остальные необязательны. Он не использует потоки или библиотеку надстройки, но достаточно гибок, чтобы можно было естественным образом принимать некоторые из этих внешних типов.