Estou tentando repetir as palavras de uma string.
Pode-se supor que a sequência seja composta por palavras separadas por espaços em branco.
Observe que não estou interessado em funções de string C ou nesse tipo de manipulação / acesso a caracteres. Além disso, priorize a elegância em detrimento da eficiência em sua resposta.
A melhor solução que tenho agora é:
#include <iostream>
#include <sstream>
#include <string>
using namespace std;
int main()
{
string s = "Somewhere down the road";
istringstream iss(s);
do
{
string subs;
iss >> subs;
cout << "Substring: " << subs << endl;
} while (iss);
}
Existe uma maneira mais elegante de fazer isso?
while (iss) { string subs; iss >> subs; cout << "Substring: " << sub << endl; }
string sub; while (iss >> sub) cout << "Substring: " << sub << '\n';
Respostas:
Para o que vale, aqui está outra maneira de extrair tokens de uma sequência de entrada, contando apenas com os recursos padrão da biblioteca. É um exemplo do poder e da elegância por trás do design do STL.
Em vez de copiar os tokens extraídos para um fluxo de saída, pode-se inseri-los em um contêiner, usando o mesmo
copy
algoritmo genérico .... ou crie o
vector
diretamente:fonte
Eu uso isso para dividir a string por um delimitador. O primeiro coloca os resultados em um vetor pré-construído, o segundo retorna um novo vetor.
Observe que esta solução não ignora tokens vazios; portanto, a seguir, você encontrará 4 itens, um dos quais está vazio:
fonte
empty()
if (!item.empty()) elems.push_back(item)
->
?f(split(s, d, v))
enquanto ainda tem o benefício de uma pré-alocação,vector
se quiser.Uma possível solução usando o Boost pode ser:
Essa abordagem pode ser ainda mais rápida que a
stringstream
abordagem. E como essa é uma função de modelo genérica, ela pode ser usada para dividir outros tipos de strings (wchar, etc. ou UTF-8) usando todos os tipos de delimitadores.Veja a documentação para detalhes.
fonte
fonte
getline
nawhile
condição, por exemplo, para dividir por vírgulas, usewhile(getline(ss, buff, ','))
.Para aqueles com quem não é bom sacrificar toda a eficiência pelo tamanho do código e ver "eficiente" como um tipo de elegância, o seguinte deve ser um ponto ideal (e acho que a classe de contêiner de modelos é uma adição incrivelmente elegante.):
Normalmente, eu escolho usar
std::vector<std::string>
tipos como meu segundo parâmetro (ContainerT
) ... maslist<>
é muito mais rápido do quevector<>
quando o acesso direto não é necessário, e você pode até criar sua própria classe de string e usar algo comostd::list<subString>
ondesubString
não faz cópias para uma velocidade incrível aumenta.É mais que o dobro da velocidade do tokenize mais rápido nesta página e quase 5 vezes mais rápido do que algumas outras. Além disso, com os tipos de parâmetros perfeitos, você pode eliminar todas as cópias de sequência e lista para aumentar a velocidade.
Além disso, ele não realiza o retorno (extremamente ineficiente) do resultado, mas passa os tokens como referência, permitindo também que você construa tokens usando várias chamadas, se assim o desejar.
Por fim, permite especificar se é necessário aparar tokens vazios dos resultados por meio de um último parâmetro opcional.
Tudo o que precisa é
std::string
... o resto é opcional. Ele não usa fluxos ou a biblioteca de reforço, mas é flexível o suficiente para poder aceitar alguns desses tipos externos naturalmente.fonte
typedef ContainerT Base; typedef typename Base::value_type ValueType; typedef typename ValueType::size_type SizeType;
Em seguida, substitua o value_type e size_types de acordo.trimEmpty = true
. Lembre-se de que"abo"
não é um delimitador nesta resposta, mas a lista de caracteres do delimitador. Seria simples para modificá-lo a tomar uma única corda delimitador de caracteres (eu acho questr.find_first_of
deve mudar parastr.find_first
, mas eu poderia ser errado ... não pode testar)Aqui está outra solução. É compacto e razoavelmente eficiente:
Pode ser facilmente modelado para lidar com separadores de cordas, cordas largas, etc.
Observe que a divisão
""
resulta em uma única cadeia vazia e a divisão","
(por exemplo, sep) resulta em duas cadeias vazias.Também pode ser facilmente expandido para pular tokens vazios:
Se você deseja dividir uma sequência em vários delimitadores enquanto ignora tokens vazios, esta versão pode ser usada:
fonte
Esta é a minha maneira favorita de percorrer uma string. Você pode fazer o que quiser por palavra.
fonte
word
como umchar
?stringstream ss("Hello World, this is*@#&$(@ a string"); char c; while(ss >> c) cout << c;
Isso é semelhante à pergunta do estouro de pilha Como faço para tokenizar uma string em C ++? .
fonte
Eu gosto do seguinte porque coloca os resultados em um vetor, suporta uma string como delim e dá controle sobre a manutenção de valores vazios. Mas, não parece tão bom então.
Obviamente, o Boost tem um
split()
que funciona parcialmente assim. E, se por 'espaço em branco', você realmente quer dizer qualquer tipo de espaço em branco, usar a divisão do Boost comis_any_of()
ótimas obras.fonte
O STL ainda não possui esse método disponível.
No entanto, você pode usar a
strtok()
função C usando ostd::string::c_str()
membro ou pode escrever sua própria. Aqui está um exemplo de código que encontrei após uma pesquisa rápida no Google ( "divisão de cadeia de caracteres STL" ):Retirado de: http://oopweb.com/CPP/Documents/CPPHOWTO/Volume/C++Programming-HOWTO-7.html
Se você tiver dúvidas sobre o exemplo de código, deixe um comentário e eu explicarei.
E só porque ele não implementa um
typedef
iterador chamado ou sobrecarrega o<<
operador não significa que seja um código incorreto. Eu uso funções C com bastante frequência. Por exemplo,printf
escanf
ambos são mais rápidos questd::cin
estd::cout
(significativamente), afopen
sintaxe é muito mais amigável para os tipos binários e eles também tendem a produzir EXEs menores.Não seja vendido neste negócio "Elegância sobre desempenho" .
fonte
Aqui está uma função dividida que:
ignora fichas vazias (pode ser facilmente alterado)
Exemplo de uso:
fonte
Eu tenho uma solução de 2 linhas para este problema:
Em vez de imprimir, você pode colocá-lo em um vetor.
fonte
Mais uma maneira flexível e rápida
Para usá-lo com um vetor de strings (Edit: Como alguém apontou para não herdar classes STL ... hrmf;)):
É isso aí! E essa é apenas uma maneira de usar o tokenizer, como contar apenas palavras:
Limitado pela imaginação;)
fonte
Appender
nota "Por que não devemos herdar uma classe das classes STL?"Aqui está uma solução simples que usa apenas a biblioteca regex padrão
O argumento regex permite verificar vários argumentos (espaços, vírgulas etc.)
Normalmente, eu só checo para dividir espaços e vírgulas, então também tenho esta função padrão:
As
"[\\s,]+"
verificações de espaços (\\s
) e vírgulas (,
).Observe que se você deseja dividir em
wstring
vez destring
,std::regex
parastd::wregex
sregex_token_iterator
parawsregex_token_iterator
Observe que você também pode usar o argumento string como referência, dependendo do seu compilador.
fonte
R"([\s,]+)"
.Usar
std::stringstream
como você funciona perfeitamente bem e fazer exatamente o que você queria. Se você está apenas procurando uma maneira diferente de fazer as coisas, pode usarstd::find()
/std::find_first_of()
estd::string::substr()
.Aqui está um exemplo:
fonte
prev_pos = pos += delimiter.length();
Se você gosta de usar o impulso, mas deseja usar uma sequência inteira como delimitador (em vez de caracteres únicos, como na maioria das soluções propostas anteriormente), você pode usar o
boost_split_iterator
.Código de exemplo, incluindo modelo conveniente:
fonte
Heres uma solução regex que usa apenas a biblioteca regex padrão. (Estou um pouco enferrujado, pode haver alguns erros de sintaxe, mas essa é pelo menos a ideia geral)
fonte
Existe uma função chamada
strtok
.fonte
strtok
é da biblioteca padrão C, não C ++. Não é seguro usar em programas multithread. Modifica a sequência de entrada.strtok
quando outro encadeamento ainda estiver sendo processado, esse ponteiro será substituído e os dois encadeamentos terão resultados incorretos. mkssoftware.com/docs/man3/strtok.3.aspO stringstream pode ser conveniente se você precisar analisar a string por símbolos que não são de espaço:
fonte
Até agora eu usei o do Boost , mas precisava de algo que não depende disso, então cheguei a isso:
Um bom ponto é que
separators
você pode passar mais de um personagem.fonte
Criei meu próprio usando strtok e usei o boost para dividir uma string. O melhor método que encontrei é a C ++ String Toolkit Library . É incrivelmente flexível e rápido.
O kit de ferramentas tem muito mais flexibilidade do que mostra este exemplo simples, mas sua utilidade na análise de uma sequência em elementos úteis é incrível.
fonte
Curto e elegante
pode usar qualquer string como delimitador, também pode ser usado com dados binários (std :: string suporta dados binários, incluindo nulos)
usando:
resultado:
fonte
Eu fiz isso porque precisava de uma maneira fácil de dividir strings e c-strings ... Espero que alguém possa achar útil também. Além disso, ele não depende de tokens e você pode usar campos como delimitadores, que é outra chave de que eu precisava.
Tenho certeza de que há melhorias que podem ser feitas para melhorar ainda mais sua elegância e, por favor, faça de todos os modos
StringSplitter.hpp:
StringSplitter.cpp:
Exemplos:
Saída:
Este
é
um
exemplo de
cstring
Para manter entradas vazias (por padrão, os vazios serão excluídos):
O objetivo era torná-lo semelhante ao método Split () do C #, onde a divisão de uma string é tão fácil quanto:
Espero que outra pessoa possa achar isso tão útil quanto eu.
fonte
Que tal isso:
fonte
Essa resposta pega a string e a coloca em um vetor de strings. Ele usa a biblioteca de impulso.
fonte
Aqui está outra maneira de fazê-lo ..
fonte
Eu gosto de usar os métodos boost / regex para esta tarefa, pois eles fornecem flexibilidade máxima para especificar os critérios de divisão.
fonte
Recentemente, tive que dividir uma palavra com camelo em subpalavras. Não há delimitadores, apenas caracteres superiores.
Por exemplo, isso divide "AQueryTrades" em "A", "Consulta" e "Negociações". A função funciona com cadeias estreitas e largas. Por respeitar o código do idioma atual, divide "RaumfahrtÜberwachungsVerordnung" em "Raumfahrt", "Überwachungs" e "Verordnung".
Nota
std::upper
deve ser realmente passada como argumento do modelo de função. Então, o mais generalizado dessa função pode ser dividido em delimitadores como","
,";"
ou" "
também.fonte
std::isupper
poderiam ser passados como argumento, nãostd::upper
. Segundo colocar umtypename
antes doString::const_iterator
.fonte
Usando
std::string_view
e arange-v3
biblioteca de Eric Niebler :https://wandbox.org/permlink/kW5lwRCL1pxjp2pW
Usando um
for
loop range em vez deranges::for_each
algoritmo:fonte