65.9K
CodeProject 正在变化。 阅读更多。
Home

STL 分隔字符串

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.33/5 (15投票s)

2001年5月15日

2分钟阅读

viewsIcon

299045

downloadIcon

77199

一个基于字符串分隔符分割输入字符串的函数。

描述

下面是我创建的一个函数,它对于基于特定分隔符分割字符串非常有用。 该实现仅需要 STL,这使得它可以轻松移植到任何支持 STL 的操作系统。 该函数相当轻量级,尽管我没有进行广泛的性能测试。

分隔符可以是由字符串表示的任意数量的字符。 然后,分隔符之间的字符串部分被放入字符串向量中。 类 StringUtils 包含一个 static 函数 SplitString。 返回的 int 是在输入字符串中找到的分隔符的数量。

我主要使用此实用程序来解析跨平台边界传递的字符串。 无论您使用的是原始套接字还是 TIBCO® 等中间件,传递字符串数据都很简单。 我发现传递分隔符分隔的字符串数据比重复调用或消息更有效。 我使用的另一个地方是在 Visual Basic 客户端和 ATL COM DLL 之间来回传递 BSTR。 事实证明,这比将 SAFEARRAY 作为 [in] 或 [out] 参数传递更容易。 当我不想添加 MFC 的额外开销,因此无法使用 CString 时,这也很有用。

实现

SplitString 函数使用 STL 字符串函数 findsubstr 来迭代输入字符串。 最困难的部分是弄清楚如何根据分隔符的偏移量获取输入字符串的子字符串,不要忘记考虑分隔符的长度。 另一个障碍是确保不要使用大于输入字符串长度的偏移量调用 substr

标题

#ifndef __STRINGUTILS_H_
#define __STRINGUTILS_H_

#include <string>
#include <vector>

using namespace std;

class StringUtils
{

public:

    static int SplitString(const string& input, 
        const string& delimiter, vector<string>& results, 
        bool includeEmpties = true);

};

#endif

来源

int StringUtils::SplitString(const string& input, 
       const string& delimiter, vector<string>& results, 
       bool includeEmpties)
{
    int iPos = 0;
    int newPos = -1;
    int sizeS2 = (int)delimiter.size();
    int isize = (int)input.size();

    if( 
        ( isize == 0 )
        ||
        ( sizeS2 == 0 )
    )
    {
        return 0;
    }

    vector<int> positions;

    newPos = input.find (delimiter, 0);

    if( newPos < 0 )
    { 
        return 0; 
    }

    int numFound = 0;

    while( newPos >= iPos )
    {
        numFound++;
        positions.push_back(newPos);
        iPos = newPos;
        newPos = input.find (delimiter, iPos+sizeS2);
    }

    if( numFound == 0 )
    {
        return 0;
    }

    for( int i=0; i <= (int)positions.size(); ++i )
    {
        string s("");
        if( i == 0 ) 
        { 
            s = input.substr( i, positions[i] ); 
        }
        int offset = positions[i-1] + sizeS2;
        if( offset < isize )
        {
            if( i == positions.size() )
            {
                s = input.substr(offset);
            }
            else if( i > 0 )
            {
                s = input.substr( positions[i-1] + sizeS2, 
                      positions[i] - positions[i-1] - sizeS2 );
            }
        }
        if( includeEmpties || ( s.size() > 0 ) )
        {
            results.push_back(s);
        }
    }
    return numFound;
}

使用演示项目的输出

main.exe "|mary|had|a||little|lamb||" "|"

int SplitString(
        const string& input,
        const string& delimiter,
        vector<string>& results,
        bool includeEmpties = true
)

-------------------------------------------------------
input           = |mary|had|a||little|lamb||
delimiter       = |
return value    = 8 // Number of delimiters found
results.size()  = 9
results[0]      = ''
results[1]      = 'mary'
results[2]      = 'had'
results[3]      = 'a'
results[4]      = ''
results[5]      = 'little'
results[6]      = 'lamb'
results[7]      = ''
results[8]      = ''

int SplitString(
        const string& input,
        const string& delimiter,
        vector<string>& results,
        bool includeEmpties = false
)

-------------------------------------------------------
input           = |mary|had|a||little|lamb||
delimiter       = |
return value    = 8 // Number of delimiters found
results.size()  = 5
results[0]      = 'mary'
results[1]      = 'had'
results[2]      = 'a'
results[3]      = 'little'
results[4]      = 'lamb'

MFC 版本

对于那些绝对不能使用 STL 并且致力于 MFC 的人,我对上述实现做了一些小的更改。 它使用 CString 代替 std::stringCStringArray 代替 std::vector

//------------------------
// SplitString in MFC
//------------------------
int StringUtils::SplitString(const CString& input, 
  const CString& delimiter, CStringArray& results)
{
  int iPos = 0;
  int newPos = -1;
  int sizeS2 = delimiter.GetLength();
  int isize = input.GetLength();

  CArray<INT, int> positions;

  newPos = input.Find (delimiter, 0);

  if( newPos < 0 ) { return 0; }

  int numFound = 0;

  while( newPos > iPos )
  {
    numFound++;
    positions.Add(newPos);
    iPos = newPos;
    newPos = input.Find (delimiter, iPos+sizeS2+1);
  }

  for( int i=0; i <= positions.GetSize(); i++ )
  {
    CString s;
    if( i == 0 )
      s = input.Mid( i, positions[i] );
    else
    {
      int offset = positions[i-1] + sizeS2;
      if( offset < isize )
      {
        if( i == positions.GetSize() )
          s = input.Mid(offset);
        else if( i > 0 )
          s = input.Mid( positions[i-1] + sizeS2, 
                 positions[i] - positions[i-1] - sizeS2 );
      }
    }
    if( s.GetLength() > 0 )
      results.Add(s);
  }
  return numFound;
}

字符串中立版本

我添加了这个版本,以防您可能需要将其用于任何类型的字符串。 唯一的要求是字符串类必须有一个接受 char* 的构造函数。 代码仅依赖于 STL 向量。 我还添加了不包含结果中空字符串的选项,如果分隔符相邻,则会发生这种情况

//-----------------------------------------------------------
// StrT:    Type of string to be constructed
//          Must have char* ctor.
// str:     String to be parsed.
// delim:   Pointer to delimiter.
// results: Vector of StrT for strings between delimiter.
// empties: Include empty strings in the results. 
//-----------------------------------------------------------
template< typename StrT >
int split(const char* str, const char* delim, 
     vector<StrT>& results, bool empties = true)
{
  char* pstr = const_cast<char*>(str);
  char* r = NULL;
  r = strstr(pstr, delim);
  int dlen = strlen(delim);
  while( r != NULL )
  {
    char* cp = new char[(r-pstr)+1];
    memcpy(cp, pstr, (r-pstr));
    cp[(r-pstr)] = '\0';
    if( strlen(cp) > 0 || empties )
    {
      StrT s(cp);
      results.push_back(s);
    }
    delete[] cp;
    pstr = r + dlen;
    r = strstr(pstr, delim);
  }
  if( strlen(pstr) > 0 || empties )
  {
    results.push_back(StrT(pstr));
  }
  return results.size();
}

字符串中立用法

// using CString
//------------------------------------------
int i = 0;
vector<CString> results;
split("a-b-c--d-e-", "-", results);
for( i=0; i < results.size(); ++i )
{
  cout << results[i].GetBuffer(0) << endl;
  results[i].ReleaseBuffer();
}

// using std::string
//------------------------------------------
vector<string> stdResults;
split("a-b-c--d-e-", "-", stdResults);
for( i=0; i < stdResults.size(); ++i )
{
  cout << stdResults[i].c_str() << endl;
}

// using std::string without empties
//------------------------------------------
stdResults.clear();
split("a-b-c--d-e-", "-", stdResults, false);
for( i=0; i < stdResults.size(); ++i )
{
  cout << stdResults[i].c_str() << endl;
}

结论

希望您觉得它和我一样有用。 欢迎您让我知道任何错误或增强功能。 享受 ;)

© . All rights reserved.