2016-04-20 13 views
4

Ich möchte die erste und letzte Klammer entfernen, die durch Referenzzeichenfolge übergeben werden. Leider habe ich Schwierigkeiten, die ersten und letzten Elemente bedingt zu entfernen. Ich kann nicht verstehen, warum remove_if nicht funktioniert, wie ich mit Iteratoren erwarte.remove_if letztes Zeichen aus einer Zeichenkette

Demo

#include <iostream> 
#include <algorithm> 
using namespace std; 

void print_wo_brackets(string& str){ 
    auto detect_bracket = [](char x){ return(')' == x || '(' == x);}; 
    if (!str.empty()) 
    { 
     str.erase(std::remove_if(str.begin(), str.begin() + 1, detect_bracket)); 
    } 
    if (!str.empty()) 
    { 
     str.erase(std::remove_if(str.end()-1, str.end(), detect_bracket)); 
    } 
} 

int main() 
{ 
    string str = "abc)"; 
    cout << str << endl; 
    print_wo_brackets(str); 
    cout << str << endl; 


    string str2 = "(abc"; 
    cout << str2 << endl; 
    print_wo_brackets(str2); 
    cout << str2 << endl; 

    return 0; 
} 

Ausgabe

abc) 
ac <- HERE I expect abc 
(abc 
abc 
+0

Diese Antwort kann nützlich sein (auch andere Antworten können passen) http://StackOverflow.com/a/25385766/3807729 – Galik

+0

Grundsätzlich remove_if ändert nicht die Größe des Containers. Stattdessen gibt es das neue Ende zurück. Sie müssen die Zeichenfolge manuell aktualisieren, um die Änderung widerzuspiegeln. Wenn Sie das erste Zeichen verwenden, wird die Saite wahrscheinlich durcheinander gebracht. –

Antwort

6

Wenn remove_if end Iterator kehrt dann versuchen, Sie nicht vorhandenes Element zu löschen. Sie sollten erase Version für Bereich in beiden Orten verwenden:

void print_wo_brackets(string& str){ 
    auto detect_bracket = [](char x){ return(')' == x || '(' == x);}; 
    if (!str.empty()) 
    { 
     str.erase(std::remove_if(str.begin(), str.begin() + 1, detect_bracket), str.begin() + 1); 
    } 
    if (!str.empty()) 
    { 
     str.erase(std::remove_if(str.end()-1, str.end(), detect_bracket), str.end()); 
    } 
} 
+0

Dies ist eigentlich eine gültige Antwort, aber in dem Beispiel zeigt 'end' auf den Buchstaben' b' (da es ein typischer Zeiger ist) –

+0

Es entfernt UB aber - Sie haben Recht, das wird Ihren Code nicht richtig laufen lassen - andere Fehler gibt es noch – marcinj

+0

@CronAcronis - ersten 'str.erase' verwendet falschen Ende Iterator Bereich, jetzt sollte es funktionieren – marcinj

4

Das Problem ist hier:

if (!str.empty()) 
{ 
    str.erase(std::remove_if(str.begin(), str.begin() + 1, detect_bracket)); 
} 

Sie bedingungslos löschen. std::remove_if gibt den Iterator an den Anfang des Bereichs "zum Entfernen" zurück. Wenn keine Elemente zum Entfernen vorhanden sind, wird das Ende des Bereichs (str.begin() + 1 in diesem Fall) zurückgegeben. So entfernen Sie begin+1 Element, das b ist.

von diesem Problem schützen Sie nicht wahrscheinlich etwas tun sollten, eher wie:

if (!str.empty()) 
{ 
    auto it = std::remove_if(str.begin(), str.begin() + 1, detect_bracket); 
    if(it != str.begin() + 1) 
     str.erase(it); 
} 

Ich nehme an, Sie einfach das Verhalten der Standard-Bibliothek überprüfen möchten und Iteratoren, da sonst überprüfen:

if(str[0] == '(' || str[0] == ')') 
    str.erase(0); 

ist viel einfacher.

+0

Aber im Falle von 'str.resease (std :: remove_if (str.begin(), str.end, detect_bracket));' Es werden alle Klammern entfernt. –

3

Alternative:

#include <iostream> 
#include <string> 

std::string without_brackets(std::string str, char beg = '(', char end = ')') { 
    auto last = str.find_last_of(end); 
    auto first = str.find_first_of(beg); 

    if(last != std::string::npos) { 
     str.erase(str.begin()+last); 
    } 
    if(first != std::string::npos) { 
     str.erase(str.begin()+first); 
    } 

    return str; 
} 


using namespace std; 

int main() { 
    cout << without_brackets("abc)") << endl 
     << without_brackets("(abc") << endl 
     << without_brackets("(abc)") << endl 
     << without_brackets("abc") << endl; 
    return 0; 
} 

siehe: http://ideone.com/T2bZDe

Ergebnis:

abc 
abc 
abc 
abc 
+0

Schöne Lösung, aber nicht mit 'remove_if' –

+0

@CronAcronis - genau. 'remove_if' ist hier das falsche Werkzeug. –

1

Alles, was Sie benötigen, ist dieses:

void print_wo_brackets(string& str){ 
    str.erase(std::remove_if(str.begin(), str.end(), 
    [&](char &c) { return (c == ')' || c == '(') && (&c == str.data() || &c == (str.data() + str.size() - 1));}), str.end()); 
} 

Live Demo

Durch die Angabe:

str.erase(std::remove_if(str.end()-1, str.end(), detect_bracket)); 

Sie evozieren nicht definiertes Verhalten.

2

Wie in den Kommentaren von @PeteBecker, remove_if, ist hier nicht der richtige Algorithmus.Da Sie nur die erste und letzte Zeichen entfernt werden soll, wenn sie übereinstimmen, eine viel einfachere Methode ist back() und front() gegen die beiden Klammern zu testen ( und ) (Klammern wäre [ und ])

void remove_surrounding(string& str, char left = '(', char right = ')') 
{ 
    if (!str.empty() && str.front() == left) 
     str.erase(str.begin()); 
    if (!str.empty() && str.back() == right) 
     str.erase(str.end() - 1); 
} 

Live Example

Verwandte Themen