paulo1205
(usa Ubuntu)
Enviado em 06/05/2018 - 14:55h
Escrevendo, agora, da casa dos meus pais, onde tenho hospedados alguns alfarrábios.
Eu trabalho muito com Perl. Por causa disso, eu desenvolvi há algum tempo umas versões de
split () semelhantes à função nativa dessa linguagem.
Em Perl, e também nas versões que mostro abaixo, a função
split () pode fazer as separações considerando como separadores uma
string exata, mesmo com múltiplos caracteres, ou uma expressão regular. Além disso, é possível dizer qual a quantidade máxima de partes depois da separação. As versões abaixo assim o fazem.
/* split.h */
#ifndef __SPLIT_H__
#define __SPLIT_H__
#include <regex>
#include <string>
#include <vector>
#define SPLIT_H_RCSHEADER "$Header: $"
std::vector<std::string> split(const std::string &str, const std::string &sep, size_t max_fields=0);
std::vector<std::string> split(const std::string &str, const std::regex &sep_re, size_t max_fields=0);
std::vector<std::string> split(const std::string &str, size_t max_fields=0);
#endif // !defined(__SPLIT_H__)
/* split.cc */
#include <regex>
#include <string>
#include <vector>
#include "split.h"
using namespace std;
namespace {
const string RCSHEADER{"$Header: $"};
const string HEADER_RCSHEADER{SPLIT_H_RCSHEADER};
}
vector<string> split(const string &str, const string &sep, size_t max_fields){
vector<string> result;
const size_t str_len=str.length();
if(str_len){
const size_t sep_len=sep.length();
const size_t empty_sep=!sep_len;
size_t a, b;
for(
a=0;
(
(max_fields==0 || result.size()<max_fields-1) &&
(b=str.find(sep, a))!=str.npos && a<str_len-sep_len
);
a=b+sep_len
){
b+=empty_sep;
result.emplace_back(str, a, b-a);
}
if((a<str.length() || (a==str.length() && result.size()<max_fields)))
result.emplace_back(str, a);
}
return result;
}
vector<string> split(const string &str, const regex &sep_re, size_t max_fields){
vector<string> result;
const size_t str_len=str.length();
if(str_len){
smatch sep;
auto a=str.begin();
while(
a!=str.end() &&
(max_fields==0 || result.size()<max_fields-1) &&
regex_search(a, str.end(), sep, sep_re)
){
result.emplace_back(a, a+sep.position(0)+!sep.length(0));
a+=sep.position(0)+sep.length(0)+!sep.length(0);
}
if((a!=str.end() || (a==str.end() && result.size()<max_fields)))
result.emplace_back(a, str.end());
}
return result;
}
vector<string> split(const string &str, size_t max_fields){
return split(str, regex("\\s+"), max_fields);
}
Exemplo de uso.
/* test.cc */
#include <iostream>
#include <regex>
#include <vector>
#include "split.h"
using namespace std;
string join(const vector<string> &v, const string &sep){
string result;
if(v.size()){
auto v_i=v.cbegin();
result=*v_i;
while(++v_i!=v.cend())
(result+=sep)+=*v_i;
}
return result;
}
void test(const string &descr, const vector<string> &v){
cout << " " << descr << " yields ";
if(v.empty())
cout << "nothing.\n";
else
cout << v.size() << " part(s): \"" << join(v, "\", \"") << "\".\n";
}
int main(){
vector<string> test_texts{
"Isto e um teste.",
"Isto e um\tteste.",
"\t\t\t Isto e um teste. ",
"\t \n \r \t",
""
};
vector<string> parts;
for(const auto &text: test_texts){
cout << "text=\"" << text << "\":\n";
test("split(text, \" \")", split(text, " "));
test("split(text, \" \", 3)", split(text, " ", 3));
test("split(text, regex(\" +\"))", split(text, regex(" +")));
test("split(text, regex(\" +\"), 3)", split(text, regex(" +"), 3));
test("split(text)", split(text));
test("split(text, 3)", split(text, 3));
cout << '\n';
}
}
Uma diferença (entre outras possíveis que eu não vi por falha minha), porém, entre a versão do Perl e a minha, é que aquela usa número de partes negativo como sinônimo de um valor arbitrariamente positivo, e a minha, por usar
size_t , não suporta valores negativos de modo nenhum. Em vez disso, alguém poderia usar
std::numeric_limits<size_t>::max() .