Как я могу токенизировать строку в C ++? - PullRequest
389 голосов
/ 10 сентября 2008

Java имеет удобный метод разделения:

String str = "The quick brown fox";
String[] results = str.split(" ");

Есть ли простой способ сделать это в C ++?

Ответы [ 35 ]

187 голосов
/ 11 сентября 2008

Класс Boost Tokenizer может упростить задачу такого рода:

#include <iostream>
#include <string>
#include <boost/foreach.hpp>
#include <boost/tokenizer.hpp>

using namespace std;
using namespace boost;

int main(int, char**)
{
    string text = "token, test   string";

    char_separator<char> sep(", ");
    tokenizer< char_separator<char> > tokens(text, sep);
    BOOST_FOREACH (const string& t, tokens) {
        cout << t << "." << endl;
    }
}

Обновлено для C ++ 11:

#include <iostream>
#include <string>
#include <boost/tokenizer.hpp>

using namespace std;
using namespace boost;

int main(int, char**)
{
    string text = "token, test   string";

    char_separator<char> sep(", ");
    tokenizer<char_separator<char>> tokens(text, sep);
    for (const auto& t : tokens) {
        cout << t << "." << endl;
    }
}
167 голосов
/ 10 сентября 2008

Вот очень просто:

#include <vector>
#include <string>
using namespace std;

vector<string> split(const char *str, char c = ' ')
{
    vector<string> result;

    do
    {
        const char *begin = str;

        while(*str != c && *str)
            str++;

        result.push_back(string(begin, str));
    } while (0 != *str++);

    return result;
}
135 голосов
/ 10 сентября 2008

Ваш простой случай может быть легко построен с использованием метода std::string::find. Однако взгляните на Boost.Tokenizer . Это великолепно. В Boost обычно есть очень крутые струнные инструменты.

107 голосов
/ 10 сентября 2008

Используйте strtok. На мой взгляд, нет необходимости создавать класс вокруг токенизации, если только strtok не предоставит вам то, что вам нужно. Возможно, нет, но за 15 с лишним лет написания различного кода синтаксического анализа на C и C ++ я всегда использовал strtok. Вот пример

char myString[] = "The quick brown fox";
char *p = strtok(myString, " ");
while (p) {
    printf ("Token: %s\n", p);
    p = strtok(NULL, " ");
}

Несколько предостережений (которые могут не соответствовать вашим потребностям). В процессе «строка» «уничтожается», что означает, что символы EOS помещаются в строку в точках разделителя. Для правильного использования может потребоваться сделать неконстантную версию строки. Вы также можете изменить список разделителей mid parse.

По моему мнению, приведенный выше код гораздо проще и проще в использовании, чем написание для него отдельного класса. Для меня это одна из тех функций, которые предоставляет язык, и делает это хорошо и чисто. Это просто решение на основе Си. Это уместно, это легко, и вам не нужно писать много лишнего кода: -)

95 голосов
/ 28 ноября 2008

Другой быстрый способ - использовать getline. Что-то вроде:

stringstream ss("bla bla");
string s;

while (getline(ss, s, ' ')) {
 cout << s << endl;
}

Если вы хотите, вы можете сделать простой split() метод, возвращающий vector<string>, который действительно полезно.

81 голосов
/ 10 сентября 2008

Вы можете использовать потоки, итераторы и алгоритм копирования, чтобы сделать это довольно напрямую.

#include <string>
#include <vector>
#include <iostream>
#include <istream>
#include <ostream>
#include <iterator>
#include <sstream>
#include <algorithm>

int main()
{
  std::string str = "The quick brown fox";

  // construct a stream from the string
  std::stringstream strstr(str);

  // use stream iterators to copy the stream to the vector as whitespace separated strings
  std::istream_iterator<std::string> it(strstr);
  std::istream_iterator<std::string> end;
  std::vector<std::string> results(it, end);

  // send the vector to stdout.
  std::ostream_iterator<std::string> oit(std::cout);
  std::copy(results.begin(), results.end(), oit);
}
46 голосов
/ 28 ноября 2008

Без обид, ребята, но для такой простой проблемы вы делаете вещи way слишком сложными. Есть много причин для использования Boost . Но для чего-то такого простого это все равно, что ударить муху санями 20 #.

void
split( vector<string> & theStringVector,  /* Altered/returned value */
       const  string  & theString,
       const  string  & theDelimiter)
{
    UASSERT( theDelimiter.size(), >, 0); // My own ASSERT macro.

    size_t  start = 0, end = 0;

    while ( end != string::npos)
    {
        end = theString.find( theDelimiter, start);

        // If at end, use length=maxLength.  Else use length=end-start.
        theStringVector.push_back( theString.substr( start,
                       (end == string::npos) ? string::npos : end - start));

        // If at end, use start=maxSize.  Else use start=end+delimiter.
        start = (   ( end > (string::npos - theDelimiter.size()) )
                  ?  string::npos  :  end + theDelimiter.size());
    }
}

Например (для Дуга),

#define SHOW(I,X)   cout << "[" << (I) << "]\t " # X " = \"" << (X) << "\"" << endl

int
main()
{
    vector<string> v;

    split( v, "A:PEP:909:Inventory Item", ":" );

    for (unsigned int i = 0;  i < v.size();   i++)
        SHOW( i, v[i] );
}

И да, мы могли бы, чтобы split () возвращала новый вектор, а не передавала его. Это тривиально для переноса и перегрузки. Но в зависимости от того, что я делаю, я часто нахожу лучше повторно использовать уже существующие объекты, чем всегда создавать новые. (Пока я не забуду опустошить вектор между ними!)

Ссылка: http://www.cplusplus.com/reference/string/string/.

(Первоначально я писал ответ на вопрос Дуга: Изменение и извлечение строк C ++ на основе разделителей (закрыто) . Но поскольку Мартин Йорк закрыл этот вопрос с помощью указателя здесь ... я просто обобщите мой код.)

34 голосов
/ 12 сентября 2008

Повышение имеет сильную функцию разделения: повышение :: алгоритм :: разделение .

Пример программы:

#include <vector>
#include <boost/algorithm/string.hpp>

int main() {
    auto s = "a,b, c ,,e,f,";
    std::vector<std::string> fields;
    boost::split(fields, s, boost::is_any_of(","));
    for (const auto& field : fields)
        std::cout << "\"" << field << "\"\n";
    return 0;
}

Выход:

"a"
"b"
" c "
""
"e"
"f"
""
34 голосов
/ 14 декабря 2014

Решение с использованием regex_token_iterator s:

#include <iostream>
#include <regex>
#include <string>

using namespace std;

int main()
{
    string str("The quick brown fox");

    regex reg("\\s+");

    sregex_token_iterator iter(str.begin(), str.end(), reg, -1);
    sregex_token_iterator end;

    vector<string> vec(iter, end);

    for (auto a : vec)
    {
        cout << a << endl;
    }
}
25 голосов
/ 04 августа 2010

Я знаю, что вы просили решение C ++, но вы могли бы счесть это полезным:

Qt

#include <QString>

...

QString str = "The quick brown fox"; 
QStringList results = str.split(" "); 

Преимущество над Boost в этом примере заключается в том, что он напрямую сопоставляется с кодом вашего сообщения.

См. Больше в Документация Qt

...