Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C++ Builder > Аналог php::explode для C++


Автор: szz 2.7.2007, 21:26
Вот.

Класс для резделения строки на части, используя разделитель - произвольную строку (строку, заметьте, а не букву!)

Путем небольших модификаций зависимость от BCB можно убрать.

Используем так:
Код

// суем:
#include "string_array.h"
....
// создаем обьект:
StringArray z;
// разбиваем:
z.explode("::", "aa::bb::cc");

// используем как хотим, например:
for(int i = 0; i < z.length(); ++i){
   std::string s = z.get(i);
   printf("строка номер %d такая: %s", i, s.c_str());
}
....
 

Сам исходник:
string_array.h
Код

//---------------------------------------------------------------------------

#ifndef string_arrayH
#define string_arrayH

#include <vcl.h>
#include <string>
#include <stdio.h>

#ifndef AS
#define AS AnsiString
#endif


AnsiString s2as(std::string a){
  AS b = a.c_str();
  return b;
}
std::string s2as(AS a){
  std::string b = a.c_str();
  return b;
}
AnsiString std_str2as(std::string a){
  return s2as(a);
}



class StringArray{
public:
    StringArray(){
        len=0;
        allocated=false;
    }
    void explode(std::string delim, std::string cont){
      if(delim=="")return;
        signed int sum=0;
        signed int loc = - signed(delim.length());
        signed int locs=0;
        do{
            locs = loc+delim.length();
            loc = cont.find( delim, locs);
            sum++;
        }while(loc != std::string::npos);
        if(allocated){
            delete [] strs;
        }
        strs = new std::string[sum];
        len = sum;
        allocated=true;
        if(cont.find( delim, 0) == std::string::npos){
            strs[0] = cont;
            return;
        }
        // now parcing again and putting all the parts:
        sum = 0;
        loc = - signed(delim.length());
        do{
            locs = loc+delim.length();
            loc = cont.find( delim, locs);
            strs[sum] = cont.substr(locs, loc-locs);
            sum++;
        }while(loc != std::string::npos);
    }
  std::string implode(std::string delim=""){
      std::string r="";
      if(!allocated)return "ERROR:not allocated";
      int i;
      for(i=0;i<length()-1;++i){
         r+=strs[i]+delim;    
      }
      return r+strs[i];
  }
    void dump(){
        printf("\nelemelts num: %d\n", len);
        if(!allocated)return;
        for(int i=0;i<length();++i){
            printf("str[%d] = %s\n", i, strs[i].c_str());
        }
    }
  std::string str(int i){
    if(allocated && i>=0 && i < length())
      return strs[i];
    return "";
  }
  std::string get(int i){ return str(i); }
  int length(){ return len; }
private:
    bool allocated;
    int len;
    std::string    *strs;
};
// и как бонус - функция - точный аналог phpшной str_replace:
AS str_replace(AS search, AS replace, AS s){
  if(!s.Pos(search)) return s;
  StringArray sa;
  sa.explode(s2as(search), s2as(s));
  return s2as(sa.implode(s2as(replace)));
}

//---------------------------------------------------------------------------
#endif

 

Автор: NFL 13.8.2011, 22:09
Отлично, как раз в bcb она мне пригодилась smile 
Спасибо  smile 

Автор: borisbn 14.8.2011, 17:04
Если автор открыт для критики, то их есть у меня smile и ооооч. много:

1. Нет деструктора, который очищал бы память выделенную под
Цитата
std::string    *strs;

2. Такой класс нельзя копировать
StringArray a;
a.explode( "::", "aa:smile::cc" );
StringArray b = a;
b.explode( " ", "aa bb cc" ); // удаление массива, выделенного для a
Цитата

        if(allocated){
            delete [] strs;
        }

3. Зачем этот изврат с динамическим массивом строк ? Почему не вектор ? Тогда бы и не нужно было бы дважды проходться по строке, деструктор сам бы всё почистил и не было бы проблемы с копированием (п.2)
4. Почему нет const
Цитата
int length() const { return len; }
и
std::string get(int i) const { return str(i); }

5. Почему строки передаются по значению, а не по ссылке ?
Цитата
void explode(std::string delim, std::string cont)

6. Что будет, если подать такую строку и разделитель
Цитата
explode( ":", "a:::b:::c" );

7. Неплохо было бы ввести флаг "выдавать пустые секции" для вариантов
Цитата
explode( ":", "a:b:c:" );
или
explode( ":", ":a:b:c" );

8. Лучше было бы, если б в классе было несколько перегруженных функций для разных разделителей: для строки (уже есть), для одиночного символа, для регулярного выражения.

Посмотри, как у профи это сделано
http://doc.qt.nokia.com/latest/qstring.html#split


NFL, не используй этот код. Он нерабочий и опасный

Автор: xvr 15.8.2011, 14:17
И еще - помесь AnsiString'а и std::string'а в одном классе выглядит несколько эклектично  smile 

Автор: volatile 15.8.2011, 21:35
Дата: 2.7.2007

Автор: NFL 16.8.2011, 14:26
Как бы работает smile 
Моя задача настолько примитивна, что его вполне достаточно smile 

Автор: borisbn 17.8.2011, 09:44
вот вариант какбэ получше smile
http://liveworkspace.org/code/187229067096e3bcb5bae250e1e4cfec
Код

#include <string>
#include <vector>
#include <deque>
#include <list>

template< typename CharT,
          class ContainerType = std::vector< std::basic_string< CharT > >
        >
class basic_string_array : public ContainerType
{
public:
    typedef std::basic_string< CharT > string_t;
    typedef typename ContainerType::iterator iterator;
    typedef typename ContainerType::const_iterator const_iterator;

    basic_string_array() {}
    basic_string_array( const string_t & inStr )
        : m_string( inStr )
    {}
    void setString( const string_t & inStr )
    {
        m_string = inStr;
    }
    string_t string() const
    {
        return m_string;
    }
    void split( const string_t & sep, bool skipEmpty = true )
    {
        split( m_string, sep, *this, skipEmpty );
    }
    static void split( const string_t & inStr, const string_t & sep, ContainerType & v, bool skipEmpty = true )
    {
        unsigned int start = 0;
        unsigned int pos = string_t::npos;
        v.clear();
        while ( ( pos = inStr.find( sep, start ) ) != string_t::npos )
        {
            string_t s = inStr.substr( start, pos - start );
            if ( ! s.empty() || ! skipEmpty )
            {
                v.push_back( s );
            }
            start = pos + sep.length();
        }
        string_t s = inStr.substr( start, pos );
        if ( ! s.empty() || ! skipEmpty )
        {
            v.push_back( s );
        }
    }
    const string_t join( const string_t & sep, bool skipEmpty = true )
    {
        m_string = join( *this, sep, skipEmpty );
        return m_string;
    }
    const string_t join( const ContainerType & v, const string_t & sep, bool skipEmpty = true )
    {
        string_t result;
        const_iterator it = v.begin();
        const_iterator theEnd = v.end();
        while ( it != theEnd )
        {
            if ( ! (*it).empty() || ! skipEmpty )
            {
                result += (*it);
                break;
            }
            ++it;
        }
        ++it;
        for ( ; it != theEnd; ++it )
        {
            const string_t & s = (*it);
            if ( ! s.empty() || ! skipEmpty )
            {
                result += sep + s;
            }
        }
        return result;
    }

private:
    string_t m_string;
};

typedef basic_string_array< char > string_vector;
typedef basic_string_array< wchar_t > wstring_vector;
typedef basic_string_array< char, std::deque< std::string > > string_deque;
typedef basic_string_array< wchar_t, std::deque< std::wstring > > wstring_deque;
typedef basic_string_array< char, std::list< std::string > > string_list;
typedef basic_string_array< wchar_t, std::list< std::wstring > > wstring_list;

#include <iostream>

int main()
{
    string_deque v( "-qwe---ewq--" );
    v.split( "-", false );
    for ( string_deque::const_iterator it = v.begin(); it != v.end(); ++it )
    {
        std::cout << (*it) << std::endl;
    }
    std::cout << v.join( "-" ) << std::endl;
}

Цитата

qwe


ewq


qwe-ewq

Автор: mihailpp 18.8.2011, 13:00
Спасибо за информацию была кое какая проблема, исправилhttp://www.world4baby.ru/

Автор: ZVano 14.9.2011, 17:33
Я сделал так (builder 2010)
Код

#include <vector.h>
#include <classes.hpp>

typedef vector<UnicodeString>TVectorOfUnicodeString;

        int Explode(UnicodeString str, UnicodeString separators, bool addEmpty, TVectorOfUnicodeString & out_result) {
            out_result.clear();
            UnicodeString curPart = "";
            int cntSeparators = 0;
            for (int cnrChars = 1; cnrChars <= str.Length(); cnrChars++) {
                UnicodeString curChar = str[cnrChars];
                if (separators.Pos(curChar) > 0) {
                    cntSeparators++;
                    if (addEmpty || (curPart.Length() > 0)) {
                        out_result.push_back(curPart);
                    }
                    curPart = "";
                    continue;
                }
                curPart += curChar;
            }
            // Докидываем последнюю часть, которая без разделителя
            if ((addEmpty & (cntSeparators > 0)) || (curPart.Length() > 0)) {
                out_result.push_back(curPart);
            }

            return out_result.size();
        }

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)