Qual è il modo più efficiente di rimuovere una "nuova riga" da una stringa std :: string?C++ Rimuovere la nuova riga da una stringa multilinea
risposta
#include <algorithm>
#include <string>
std::string str;
str.erase(std::remove(str.begin(), str.end(), '\n'), str.end());
Il comportamento di std :: remove potrebbe non essere del tutto ciò che vi aspettereste. Vedere una spiegazione di esso here.
Se c'è qualche possibilità di newline da altre piattaforme, forse cancella anche i caratteri '\ r'. Una seconda chiamata per cancellare e std :: remove etc non rappresenta un grosso vantaggio per quanto riguarda le prestazioni. Le alternative, come l'uso di std :: remove_if con una funzione di predicato, saranno probabilmente più lente. – Steve314
Se i tuoi dati sono stati originariamente caricati da un file aperto in modalità testo (ascii, non binario) credo che converta automaticamente tutte le convenzioni di nuova riga in un semplice '\ n'. Sto cercando un riferimento definitivo a corroborare. – luke
http://msdn.microsoft.com/en-us/library/kt0etdcs%28VS.71%29.aspx - thats per fread(), ma credo che iostream letture e scritture abbiano lo stesso comportamento. – luke
Se è ovunque nella stringa di quanto tu non possa fare meglio di O (n).
E l'unico modo è cercare '\ n' nella stringa e cancellarlo.
for(int i=0;i<s.length();i++) if(s[i]=='\n') s.erase(s.begin()+i);
Per maggiori ritorni a capo di:
int n=0;
for(int i=0;i<s.length();i++){
if(s[i]=='\n'){
n++;//we increase the number of newlines we have found so far
}else{
s[i-n]=s[i];
}
}
s.resize(s.length()-n);//to delete only once the last n elements witch are now newlines
cancella tutti i ritorni a capo una volta.
Questa implementazione non gestirà correttamente i newline consecutivi, poiché 'i' viene incrementato indipendentemente dal fatto che un elemento sia cancellato. –
Ho appena notato, modifico questa – csiz
Se la nuova linea dovrebbe essere alla fine della stringa, quindi:
if (!s.empty() && s[s.length()-1] == '\n') {
s.erase(s.length()-1);
}
Se la stringa può contenere molti ritorni a capo in qualsiasi punto della stringa:
std::string::size_type i = 0;
while (i < s.length()) {
i = s.find('\n', i);
if (i == std::string:npos) {
break;
}
s.erase(i);
}
Prima versione perfetta. Seconda versione sarebbe più facile da usare std :: erase (std :: removr (XXX)) –
Non mi sono mai sentito molto a mio agio con la semantica di remove() e devo sempre cercare perché non è ovvio. La mia implementazione sopra è semplice e diretta, ma non la più efficiente. Se l'efficienza è importante, è necessaria una soluzione leggermente diversa. –
la domanda era "qual è il modo più efficiente ...", quindi immagino che l'efficienza sia importante;) – Pieter
si dovrebbe usare il erase-remove idiom, cercando '\n'
. Questo funzionerà per qualsiasi contenitore di sequenze standard; non solo string
.
Utilizzare std :: algoritmi. Questa domanda ha alcuni suggerimenti opportunamente riutilizzabili Remove spaces from std::string in C++
s.erase(std::remove(s.begin(), s.end(), '\n'), s.end());
Il codice rimuove tutte newline dalla stringa str
.
O (N) implementazione migliore senza commenti su SO e con commenti in produzione.
unsigned shift=0;
for (unsigned i=0; i<length(str); ++i){
if (str[i] == '\n') {
++shift;
}else{
str[i-shift] = str[i];
}
}
str.resize(str.length() - shift);
std::string some_str = SOME_VAL;
if (some_str.size() > 0 && some_str[some_str.length()-1] == '\n')
some_str.resize(some_str.length()-1);
o (rimuove diverse a capo alla fine)
some_str.resize(some_str.find_last_not_of(L"\n")+1);
Tutte queste risposte sembrano un po 'pesante per me.
Se togli semplicemente il "\ n" e sposta tutto il resto in un punto, è probabile che alcuni personaggi vengano sbattuti insieme in un modo strano. Quindi, perché non fare la semplice (e più efficiente) cosa: Sostituisci tutti \ n con gli spazi?
for (int i = 0; i < str.length();i++) {
if (str[i] == '\n') {
str[i] = ' ';
}
}
Ci possono essere modi per migliorare la velocità di questo ai bordi, ma sarà modo più veloce di muoversi intere porzioni della stringa intorno in memoria.
Ecco uno per DOS o Unix nuova linea:
void chomp(string &s)
{
int pos;
if((pos=s.find('\n')) != string::npos)
s.erase(pos);
}
Cambia il ciclo' if' in un 'while' e hai una soluzione piuttosto buona. – CaptainBli
Un altro modo per farlo nel ciclo for
void rm_nl(string &s) {
for (int p = s.find("\n"); p != (int) string::npos; p = s.find("\n"))
s.erase(p,1);
}
Usage:
string data = "\naaa\nbbb\nccc\nddd\n";
rm_nl(data);
cout << data; // data = aaabbbcccddd
su RISPOSTA 3 rimuovendo solo l'ultimo \ n codice stringa off:
if (!s.empty() && s[s.length()-1] == '\n') {
s.erase(s.length()-1);
}
La condizione if non fallirà se la stringa è veramente vuota?
Non è meglio fare:
if (!s.empty())
{
if (s[s.length()-1] == '\n')
s.erase(s.length()-1);
}
È disposta la nuova linea dovrebbe essere in un luogo particolare, come ad esempio alla fine della stringa? –
no; potrebbe essere ovunque – shergill