如何在C ++中标记字符串?

时间:2020-03-05 18:50:40  来源:igfitidea点击:

Java有一个方便的split方法:

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

有没有一种简单的方法可以在C ++中做到这一点?

解决方案

回答

没有直接的方法可以做到这一点。请参考此代码项目源代码,以了解如何为此构建类。

回答

这是一个示例令牌生成器类,可能会做我们想要的

//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());
}

回答

我们可以使用std :: string :: find方法轻松构建简单的案例。但是,请看一下Boost.Tokenizer。这很棒。 Boost通常具有一些非常酷的字符串工具。

回答

如果我们愿意使用C,则可以使用strtok函数。使用它时,应注意多线程问题。

回答

这是一个真正简单的例子:

#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;
}

回答

我认为这就是字符串流上的>>运算符的作用:

string word; sin >> word;

回答

我们可以使用流,迭代器和复制算法直接进行此操作。

#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);
}

回答

使用strtok。在我看来,除非strtok不能为我们提供所需的内容,否则无需围绕标记化构建类。可能不是,但是在用C和C ++编写各种解析代码的15年以上的时间里,我一直使用strtok。这是一个例子

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

一些警告(可能不适合需求)。该字符串在此过程中被"销毁",这意味着EOS字符被内联放置在除臭点中。正确的用法可能要求我们制作字符串的非常量版本。我们还可以更改中间解析的定界符列表。

我个人认为,与编写单独的类相比,以上代码更简单,更易于使用。对我来说,这是该语言提供的功能之一,它做得很好而且干净利落。它只是一个"基于C"的解决方案。这很合适,很容易,而且我们不必编写很多额外的代码:-)

回答

Boost令牌生成器类可以使这种事情变得非常简单:

#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;
    }
}

回答

Boost具有强大的拆分功能:boost :: algorithm :: 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"
""

回答

对于简单的东西,我只使用以下内容:

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;
}

怯ward的免责声明:我编写了实时数据处理软件,其中的数据通过二进制文件,套接字或者某些API调用(I / O卡,相机的)传入。与启动时读取外部配置文件相比,我从未将此功能用于更复杂或者对时间要求不高的事情。

回答

没有冒犯性的人,但是对于这样一个简单的问题,我们使事情变得太复杂了。有很多原因使用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 ++字符串修改和提取。

回答

另一种快速的方法是使用getline。就像是:

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

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

如果需要,可以制作一个简单的split()方法,返回一个vector &lt;string>,即
真的很有用。

回答

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

回答

我知道我们要求使用C ++解决方案,但是我们可能会认为这很有帮助:

t

#include <QString>

...

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

在本示例中,与Boost相比的优势在于,它是直接映射到帖子代码。

在Qt文档中查看更多

回答

检查此示例。它可能会。

#include <iostream>
#include <sstream>

using namespace std;

int main ()
{
    string tmps;
    istringstream is ("the dellimiter is the space");
    while (is.good ()) {
        is >> tmps;
        cout << tmps << "\n";
    }
    return 0;
}