Как я могу токенизировать строку в C ++?

Вы можете проверить срок службы, используя

bool isProcessRunning(HANDLE process)
{
   return WaitForSingleObject( process, 0 ) == WAIT_TIMEOUT;
}
394
задан DavidRR 4 April 2013 в 18:04
поделиться

16 ответов

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

138
ответ дан Juan Carlos Ramirez 4 April 2013 в 18:04
поделиться

Нет никакого прямого способа сделать это. Пошлите этот исходный код проекта кода узнать, как создать класс для этого.

1
ответ дан Niyaz 4 April 2013 в 18:04
поделиться

Я думал, для именно это >> был оператор на строковых потоках:

string word; sin >> word;
4
ответ дан Felix Dombek 4 April 2013 в 18:04
поделиться

Для простого материала я просто использую следующее:

unsigned TokenizeString(const std::string& i_source,
                        const std::string& i_seperators,
                        bool i_discard_empty_tokens,
                        std::vector<std::string>& o_tokens)
{
    unsigned prev_pos = 0;
    unsigned pos = 0;
    unsigned number_of_tokens = 0;
    o_tokens.clear();
    pos = i_source.find_first_of(i_seperators, pos);
    while (pos != std::string::npos)
    {
        std::string token = i_source.substr(prev_pos, pos - prev_pos);
        if (!i_discard_empty_tokens || token != "")
        {
            o_tokens.push_back(i_source.substr(prev_pos, pos - prev_pos));
            number_of_tokens++;
        }

        pos++;
        prev_pos = pos;
        pos = i_source.find_first_of(i_seperators, pos);
    }

    if (prev_pos < i_source.length())
    {
        o_tokens.push_back(i_source.substr(prev_pos));
        number_of_tokens++;
    }

    return number_of_tokens;
}

Трусливая правовая оговорка: Я пишу программное обеспечение обработки данных реального времени, где данные входят через двоичные файлы, сокеты или некоторый вызов API (Платы ввода-вывода, камера). Я никогда не использую эту функцию для чего-то более сложного или строго ограниченного во времени, чем чтение внешних конфигурационных файлов на запуске.

4
ответ дан jilles de wit 4 April 2013 в 18:04
поделиться

Если Вы готовы использовать C, можно использовать функция strtok. Необходимо обратить внимание на проблемы многопоточности при использовании его.

4
ответ дан On Freund 4 April 2013 в 18:04
поделиться

Не обижайтесь, ребята, но для такой простой задачи вы делаете вещи более сложными . Есть много причин использовать 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 ++ на основе разделителей (закрыто) . Но поскольку Мартин Йорк закрыл этот вопрос с помощью указателя здесь ... просто обобщите мой код.)

46
ответ дан Community 4 April 2013 в 18:04
поделиться

pystring - это небольшая библиотека, которая реализует набор строковых функций Python, включая метод split:

#include <string>
#include <vector>
#include "pystring.h"

std::vector<std::string> chunks;
pystring::split("this string", chunks);

// also can specify a separator
pystring::split("this-string", chunks, "-");
16
ответ дан dbr 4 April 2013 в 18:04
поделиться

Вот пример класса токенизатора, который может делать то, что вы хотите

//Header file
class Tokenizer 
{
    public:
        static const std::string DELIMITERS;
        Tokenizer(const std::string& str);
        Tokenizer(const std::string& str, const std::string& delimiters);
        bool NextToken();
        bool NextToken(const std::string& delimiters);
        const std::string GetToken() const;
        void Reset();
    protected:
        size_t m_offset;
        const std::string m_string;
        std::string m_token;
        std::string m_delimiters;
};

//CPP file
const std::string Tokenizer::DELIMITERS(" \t\n\r");

Tokenizer::Tokenizer(const std::string& s) :
    m_string(s), 
    m_offset(0), 
    m_delimiters(DELIMITERS) {}

Tokenizer::Tokenizer(const std::string& s, const std::string& delimiters) :
    m_string(s), 
    m_offset(0), 
    m_delimiters(delimiters) {}

bool Tokenizer::NextToken() 
{
    return NextToken(m_delimiters);
}

bool Tokenizer::NextToken(const std::string& delimiters) 
{
    size_t i = m_string.find_first_not_of(delimiters, m_offset);
    if (std::string::npos == i) 
    {
        m_offset = m_string.length();
        return false;
    }

    size_t j = m_string.find_first_of(delimiters, i);
    if (std::string::npos == j) 
    {
        m_token = m_string.substr(i);
        m_offset = m_string.length();
        return true;
    }

    m_token = m_string.substr(i, j - i);
    m_offset = j;
    return true;
}

Пример:

std::vector <std::string> v;
Tokenizer s("split this string", " ");
while (s.NextToken())
{
    v.push_back(s.GetToken());
}
22
ответ дан vzczc 4 April 2013 в 18:04
поделиться

Ускорение имеет функцию сильного разделения: boost ::gorith :: split .

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

#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
ответ дан congusbongus 4 April 2013 в 18:04
поделиться

Еще один быстрый способ - использовать getline. Примерно так:

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

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

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

97
ответ дан Dominic Rodger 4 April 2013 в 18:04
поделиться

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

#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);
}
81
ответ дан KeithB 4 April 2013 в 18:04
поделиться

токенизатор Повышения класс может сделать этот вид вещи довольно простым:

#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;
    }
}
187
ответ дан Ferruccio 4 April 2013 в 18:04
поделиться

Используйте 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, " ");
}

Несколько протестов (который не мог бы удовлетворить Вашим потребностям). Строка "уничтожается" в процессе, означая, что символы ЭОС помещаются встроенные в местах delimter. Корректное использование могло бы потребовать, чтобы Вы сделали версию неконстанты строки. Можно также изменить список разделителей середина синтаксического анализа.

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

108
ответ дан Mark 4 April 2013 в 18:04
поделиться

Вот реальный простой:

#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;
}
167
ответ дан Oktalist 4 April 2013 в 18:04
поделиться

MFC/ATL имеет очень хороший токенизатор. Из MSDN:

CAtlString str( "%First Second#Third" );
CAtlString resToken;
int curPos= 0;

resToken= str.Tokenize("% #",curPos);
while (resToken != "")
{
   printf("Resulting token: %s\n", resToken);
   resToken= str.Tokenize("% #",curPos);
};

Output

Resulting Token: First
Resulting Token: Second
Resulting Token: Third
5
ответ дан Jim In Texas 5 April 2013 в 05:04
поделиться

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

Qt

#include <QString>

...

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

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

Подробнее см. Документация Qt

25
ответ дан 22 November 2019 в 23:40
поделиться
Другие вопросы по тегам:

Похожие вопросы: