C++ 带两个分隔符的stringstream

C++ 带两个分隔符的stringstream,c++,delimiter,stringstream,C++,Delimiter,Stringstream,我试图先使用第一个分隔符对字符串进行分隔,然后再使用第二个分隔符。我试图尽量减少使用的资源,避免不必要的循环(然后我也不确定需要多少循环)。我也是一个相当新的C++程序员。下面的函数显示了我当前使用的代码 vector<string> dualDelimit(string str,char del1,char del2) { vector<string> sub; stringstream ss(str); stringstream ss2;

我试图先使用第一个分隔符对字符串进行分隔,然后再使用第二个分隔符。我试图尽量减少使用的资源,避免不必要的循环(然后我也不确定需要多少循环)。我也是一个相当新的C++程序员。下面的函数显示了我当前使用的代码

vector<string> dualDelimit(string str,char del1,char del2)
{
    vector<string> sub;
    stringstream ss(str);
    stringstream ss2;
    while(ss.good())
    {
        string substring;
        getline(ss,substring,del1);

        ss2<<substring;
        while(ss2.good())
        {
            getline(ss2,substring,del2);
            sub.push_back(substring);
        }
    }
    return sub;
}
打印并存储在结果向量中的结果仅为:

This
is
从ss中提取的第一个字符串似乎随后用第二个分隔符分隔,其子字符串通常添加到向量中,但第一个字符串似乎会停止,并且不会通过其余字符串。
是什么导致了这种行为?函数的第一个while何时中断,如何中断

我已经用了很长时间了,效果很好

实用程序.h

#ifndef UTILITY_H
#define UTILITY_H

class Utility {
public:
    Utility() = delete;
    Utility( const Utility& ) = delete;
    Utility& operator=( const Utility& ) = delete;

    static std::string trim( const std::string& str, 
                             const std::string elementsToTrim = " \t\n\r" ); 

    static std::vector<std::string> splitString( const std::string& stringToSplit, 
                                                 const std::string& strDelimiter, 
                                                 const bool keepEmpty = true );    
};

#endif // !UTILITY_H
您可以轻松地将
stringstream
替换为这个splitString()算法,只需在需要的地方使用它的str()函数


<> > >编辑< <强> >用户:<代码> Christian Hackl < /C> >抱怨我在类中包含所有相关的静态函数,并称使用命名空间,因为这是C++而不是java。就我个人而言,我看不出有什么大不了的,但如果有问题,您可以删除包装类实用程序,并将所有通常相关的独立函数放在
名称空间中


最后一个注释:

在我的原始类
实用工具
中,包含了用于处理字符串的静态方法,由于特定的原因,我将它们放在类中,而不仅仅是驻留在命名空间中的独立函数

用户–Christian Hackl表示:

“从来没有创建过Util对象;它有点像命名空间。”-然后使用实际的命名空间。正如我所说,这不是Java

我会反对的。不要误解我;命名空间是C++的重要和重要部分,应该在适当的时候使用。但是,在某些情况下,名称空间是不够的,所需的语言和编译器机制需要类或结构的形式。我这是什么意思?这是一个稍微高级一点的主题,但非常简单。你看,在我的班上,我提供的;我只展示了这个类中的几个函数。我有十几个其他函数,其中一些是函数模板。因此,在名称空间中有一个单独的函数模板也可以说是相同的。我班的情况不是这样。我的类有两个私有函数模板,用于将字符串作为输入,并将其转换为默认的基本类型(int、unsigned、float、double等)。我甚至拥有将字符串转换为
glm::vec2
vec3
vec4
glm::ivec2
ivec3
ivec4
glm::mat3
,这些函数遵循相同的约定

这些转换函数调用获取该类型值的函数模板,但它依赖于函数模板专门化;这不能在命名空间中完成。如果您尝试在没有类或结构的情况下执行此操作;代码将被编译,但您将得到链接器错误,因为模板的参数列表不能接受名称空间;但它可以接受类、结构或整数类型

下面是一个伪示例:

{    // header file
     ...
     static int converToInt( const std::string& str );
     static float convertToFloat( const std::string& str );
private:
     template<typename T>
     bool hasValue( const std::string& str, T* pValue );

     template<typename T>
     T getValue( const std::string );
}


// *.inl file
template<typename T>
bool Utility::hasValue( const std::string& str, T* pValue ) {
    // string manipulation
    pValue[0] = getValue<T>( str );

    // check some condition return true or false
}

// *.cpp file
int convertToInt( const std::string& str ) {
   // return converted int from string
}

float convertToFloat( const std::string& str ) {
   // return converted float from string
}

template<>
int getValue( const std::string& ) {
    return int that was converted from (convertToInt)
}

template<>
float getValue( const std::string& ) {
    return float that was converted from (convertToFloat)
}
{//头文件
...
静态int转换点(const std::string&str);
静态浮点转换浮点(const std::string&str);
私人:
模板
bool hasValue(const std::string&str,T*pValue);
模板
T getValue(const std::string);
}
//*.inl文件
模板
bool实用工具::hasValue(const std::string&str,T*pValue){
//字符串操作
pValue[0]=getValue(str);
//检查某些条件是否返回true或false
}
//*.cpp文件
int convertToInt(常量std::string和str){
//从字符串返回转换后的整数
}
float convertToFloat(const std::string和str){
//从字符串返回已转换的浮点
}
模板
int getValue(const std::string&){
返回从转换而来的int(convertToInt)
}
模板
float getValue(const std::string&){
从(convertToFloat)转换的返回浮点
}
您不能在类之外而仅在命名空间中执行此操作。这就是为什么我的函数在最初的演示中是不可构造类中的静态方法

这里之所以需要这种模式,是因为
getValue()
函数在所有情况下都将字符串作为其参数,但唯一的区别是返回类型。在C++和其他大多数语言中,不能仅在返回类型上执行过载解析。它可能最终成为一个模棱两可的调用,或者如果从未使用返回类型;编译器甚至可能不会首先调用该函数。所以为了模拟这个,;其中函数需要是模板类型;为了专门化这些函数,它们需要包含在类中,否则不能专门化仅在命名空间中的函数模板


关于
这是C++
而不是
Java
的整个评论确实是一个糟糕的评估。为什么?不要以任何形式或形式贬低用户,但该声明似乎完全有偏见。第一;将静态方法放入没有任何成员的结构或类中,使构造函数私有化是完全合法有效的C++代码。p> 它与Java没有任何关系;坦率地说,我从来没有用Java编程过任何东西。我只在C和C++编程过。我在90年代末高中时在Visual Basic和C语言中做过几项小应用,但在过去的2年中,它一直是C++的95%。你是对的,这是C++
#ifndef UTILITY_H
#define UTILITY_H

class Utility {
public:
    Utility() = delete;
    Utility( const Utility& ) = delete;
    Utility& operator=( const Utility& ) = delete;

    static std::string trim( const std::string& str, 
                             const std::string elementsToTrim = " \t\n\r" ); 

    static std::vector<std::string> splitString( const std::string& stringToSplit, 
                                                 const std::string& strDelimiter, 
                                                 const bool keepEmpty = true );    
};

#endif // !UTILITY_H
#include "Utility.h"

#include <vector>
#include <string>
#include <algorithm>

std::string Utility::trim( const std::string& str, 
                          const std::string elementsToTrim ) {
    std::basic_string<char>::size_type firstIndex = str.find_first_not_of( elementsToTrim );
    if ( firstIndex == std::string::npos )
        return std::string(); // Nothing Left    
    std::basic_string<char>::size_type lastIndex = str.find_last_not_of( elementsToTrim );
    return str.substr( firstIndex, lastIndex - firstIndex + 1 );
}

std::vector<std::string> Utility::splitString( const std::string& strStringToSplit, 
                                               const std::string& strDelimiter, 
                                               const bool keepEmpty ) {
    std::vector<std::string> vResult;
    if ( strDelimiter.empty() ) {
        vResult.push_back( strStringToSplit );
        return vResult;
    }    
    std::string::const_iterator itSubStrStart = strStringToSplit.begin(), itSubStrEnd;
    while ( true ) {
        itSubStrEnd = search( itSubStrStart, strStringToSplit.end(), strDelimiter.begin(), strDelimiter.end() );
        std::string strTemp( itSubStrStart, itSubStrEnd );
        if ( keepEmpty || !strTemp.empty() )
            vResult.push_back( strTemp );
        if ( itSubStrEnd == strStringToSplit.end() )
            break;
        itSubStrStart = itSubStrEnd + strDelimiter.size();
    }    
    return vResult;    
}
#include <iostream>
#include <vector>
#include <string>

#include "Utility.h"

int main() {
    std::vector<std::tring> result;
    std::string str( "This|is;a|test." );
    std::cout << str << std::endl;

    result = Utility::splitString( str, ";" );

    str.clear();
    for ( auto& s : result )
        str += s + " ";
    std::cout << str << std::endl;

    result.clear();
    result = Utility::splitString( str, "|" );

    str.clear();
    for ( auto& s : result )
        str += s + " ";
    std::cout << str << std::endl;

    system( "PAUSE" );
    return 0;
}
{
    // [...]

    str.clear();
    result.clear();

    str = std::string( "cruelcruelhellocruelcruelmadryochcruel" );
    result = Utility::splitString( str,  "cruel" );
    str.clear();
    for ( auto& s : result )
        str += s + " ";
    str = Utility::trim( str );
    std::cout << str << std::endl;

    system( "PAUSE" );
    return 0;
}
splitString( s, "a" )   = "well   bbbdone"
               "aa"     = "well abbbdone"
               "aaa"    = "well bbbdone";
               "ab"     = "wellaa bbdone";      
               "aabb"   = "wella bdone";
               "aaabbb" = "well done";
// without calling trim.* This may not be accurate; I did add it & removed it
// several times; but you should still get the idea.
// Utility.h
#ifndef UTILITY_H
#define UTILITY_H

namespace util {
    // function declarations;

} // namespace util 

#endif // !UTILITY_H 

//===================================

// Utility.cpp
#include "Utility.h"
// One of tree ways here:

// First:
using namespace util;

// function definitions;

// Second:
util::function definitions

// Third: 
namespace util {
    // function definitions
} // namespace util
{    // header file
     ...
     static int converToInt( const std::string& str );
     static float convertToFloat( const std::string& str );
private:
     template<typename T>
     bool hasValue( const std::string& str, T* pValue );

     template<typename T>
     T getValue( const std::string );
}


// *.inl file
template<typename T>
bool Utility::hasValue( const std::string& str, T* pValue ) {
    // string manipulation
    pValue[0] = getValue<T>( str );

    // check some condition return true or false
}

// *.cpp file
int convertToInt( const std::string& str ) {
   // return converted int from string
}

float convertToFloat( const std::string& str ) {
   // return converted float from string
}

template<>
int getValue( const std::string& ) {
    return int that was converted from (convertToInt)
}

template<>
float getValue( const std::string& ) {
    return float that was converted from (convertToFloat)
}