Wie implementiere ich Folgendes (Python-Pseudocode) in C ++?
if argv[1].startswith('--foo='):
foo_value = int(argv[1][len('--foo='):])
(Wenn beispielsweise argv[1]
ist --foo=98
, dann foo_value
ist 98
.)
Update: Ich zögere, mich mit Boost zu befassen, da ich nur eine sehr kleine Änderung an einem einfachen kleinen Befehlszeilentool vornehmen möchte (ich möchte lieber nicht lernen, wie man Boost für Minderjährige verknüpft und verwendet Veränderung).
Antworten:
Verwenden Sie eine Überladung
rfind
mit dempos
Parameter:Wer braucht noch etwas? Pure STL!
Viele haben dies falsch verstanden, um "rückwärts durch die gesamte Zeichenfolge nach dem Präfix suchen" zu bedeuten. Dies würde zu einem falschen Ergebnis führen (z. B. würde
string("tititito").rfind("titi")
2 im Vergleich zu== 0
false zurückgeben) und wäre ineffizient (Blick auf die gesamte Zeichenfolge anstatt nur auf den Anfang). Dies ist jedoch nicht der Fall, da derpos
Parameter als übergeben wird0
, wodurch die Suche auf eine Übereinstimmung nur an dieser Position oder früher beschränkt wird . Beispielsweise:quelle
find
ist nur dann Null, wenn ertiti
am Anfang der Zeichenfolge steht. Wenn es woanders gefunden wird, erhalten Sie einen Rückgabewert ungleich Null, und wenn es nicht gefunden wird, erhalten Sie einen Wert,npos
der ebenfalls ungleich Null ist. Angenommen, ich habe Recht, würde ich diese Antwort vorziehen, da ich keine nicht standardmäßigen Dinge einbringen muss (ja, ich weiß, dass Boost überall ist, ich würde nur einfache C ++ - Bibliotheken für einfache Dinge wie diese bevorzugen).titi
, aber der Konvertierungsteil fehlt.rfind()
, die keinenpos
Parameter akzeptiert . Wenn Sie die Überladung verwenden, die einenpos
Parameter benötigt, wird nicht die gesamte Zeichenfolge durchsucht, sondern nur diese Position und früher. (Genau wie regulärfind()
mitpos
Parameter nur an dieser Position oder später aussieht.) Wenn Sie also bestehenpos == 0
, wie in dieser Antwort gezeigt, wird es buchstäblich nur für Übereinstimmungen an dieser einen Position berücksichtigt. Das wurde bereits in der Antwort und in den Kommentaren erklärt.Du würdest es so machen:
Es ist auch eine gute Idee, nach einer Bibliothek wie Boost.ProgramOptions zu suchen, die dies für Sie erledigt.
quelle
atoi("123xyz")
Rückkehr123
, während Pythonsint("123xyz")
eine Ausnahme auslöst.atoi
mitstrtol
oderstrtoll
, was lässt uns Fehlerbedingungen in dem Eingabewert erkennen.rfind
, die von der Optimierung abhängt, um zu funktionieren.Der Vollständigkeit halber werde ich die C-Methode erwähnen:
(ursprünglich von Yaseen Rauf hier gepostet , Markup hinzugefügt)
Verwenden Sie für einen Vergleich ohne Berücksichtigung der Groß- und Kleinschreibung
strnicmp
anstelle vonstrncmp
.Dies ist die C-Methode. Für C ++ - Zeichenfolgen können Sie dieselbe Funktion wie folgt verwenden:
quelle
memcmp()
Wenn Sie Boost bereits verwenden, können Sie dies mit Boost-String-Algorithmen + Boost-Lexikon-Cast tun :
Diese Art von Ansatz ist, wie viele der anderen hier bereitgestellten Antworten, für sehr einfache Aufgaben in Ordnung, aber auf lange Sicht ist es normalerweise besser, eine Befehlszeilen-Analysebibliothek zu verwenden. Boost hat eine ( Boost.Program_options ), die sinnvoll sein kann, wenn Sie Boost bereits verwenden.
Andernfalls bietet eine Suche nach "c ++ - Befehlszeilenparser" eine Reihe von Optionen.
quelle
Code, den ich selbst benutze:
quelle
substr
führt zu unnötigem Kopieren. Diestr.compare(start, count, substr)
in Thomas 'Antwort verwendete Methode ist effizienter. Die Antwort von razvanco13 enthält eine andere Methode, mit der das Kopieren mit vermieden wirdstd::equal
.Thomas uses atoi which is only for windows
Huh?atoi
ist seit ... je eine C-Standard-Bibliotheksfunktion. In der Tatatoi
ist es schlecht - nicht weil es Windows-spezifisch ist - sondern weil es (1) C, nicht C ++ und (2) sogar in C veraltet ist (Sie solltenstrtol
oder eine der anderen verwandten Funktionen verwenden. Weilatoi
hat Keine Fehlerbehandlung. Aber auch das ist sowieso nur in C.Bisher hat noch niemand die STL- Algorithmus / Mismatch- Funktion verwendet. Wenn dies true zurückgibt, ist das Präfix ein Präfix von 'toCheck':
Vollständiges Beispiel-Prog:
Bearbeiten:
Wie @James T. Huggett vorschlägt, passt std :: gleich besser zu der Frage: Ist A ein Präfix von B? und ist etwas kürzer Code:
Vollständiges Beispiel-Prog:
quelle
std::equal
für Zeichenfolgen hat den Nachteil, dass das Zeichenfolgenende nicht erkannt wird. Sie müssen daher manuell prüfen, ob das Präfix kürzer als die gesamte Zeichenfolge ist. (Wie im Beispiel-Prog richtig gemacht, aber im Einzeiler oben weggelassen.)Angesichts der Tatsache, dass beide Zeichenfolgen -
argv[1]
und"--foo"
- C-Zeichenfolgen sind, ist die Antwort von @ FelixDombek zweifellos die beste Lösung.Angesichts der anderen Antworten hielt ich es jedoch für erwähnenswert, dass es
std::string
eine einfache, maximal kopierfähige, maximal effiziente Lösung gibt, die bisher noch nicht erwähnt wurde , wenn Ihr Text bereits als verfügbar ist:Und wenn foo schon ein String ist:
quelle
rfind(x, 0) == 0
sollte wirklich im Standard definiert werden alsstarts_with
rfind()
(anstelle vonstartswith()
) sehr ineffizient ist - es wird bis zum Ende der Zeichenfolge gesucht.Mit C ++ 17 können Sie
std::basic_string_view
& mit C ++ 20std::basic_string::starts_with
oder verwendenstd::basic_string_view::starts_with
.Der Vorteil
std::string_view
im Vergleich zustd::string
- in Bezug auf die Speicherverwaltung - besteht darin, dass es nur einen Zeiger auf eine "Zeichenfolge" (zusammenhängende Folge von char-ähnlichen Objekten) enthält und deren Größe kennt. Beispiel ohne Verschieben / Kopieren der Quellzeichenfolgen, um den ganzzahligen Wert zu erhalten:quelle
std::atoi
ist völlig in Ordnung. Bei schlechten Eingaben (die in diesem Code behandelt werden) werden Ausnahmen ausgelöst. Hattest du noch etwas anderes im Sinn?atoi
von<cstdlib>
? In der Dokumentation heißt es "es werden niemals Ausnahmen ausgelöst".atoi
stattstd::atoi
. Der erste ist unsicher zu verwenden, während der zweite in Ordnung ist. Ich verwende letzteres im Code hier.std::atoi
tatsächlich eine Ausnahme darstellt, indem Sie eine geeignete Referenz angeben. Bis du es tust, glaube ich dir nicht, da es sehr verwirrend wäre, beides zu haben::atoi
undstd::atoi
ganz anders zu handeln.std::atoi
das anstelle von verwendet wurdestd::stoi
. Ich habe das behoben.quelle
if (one-liner)
Mit STL könnte dies so aussehen:
quelle
if (prefix.size()<=arg.size() && std::equal(...))
.Dieses
sscanf
Beispiel ist meiner Meinung nach eleganter als die meisten Boost-Lösungen, da die Gefahr besteht, dass es für die Verwendung von C-Konstrukten in Flammen steht. Und Sie müssen sich keine Gedanken über die Verknüpfung machen, wenn Sie irgendwo mit einem Python-Interpreter arbeiten!Hier ist eine Beispielausgabe, die zeigt, dass die Lösung führenden / nachfolgenden Müll genauso korrekt behandelt wie den entsprechenden Python-Code und korrekter als alles,
atoi
was verwendet wird (wodurch ein nicht numerisches Suffix fälschlicherweise ignoriert wird).quelle
argv[i]
ist"--foo=9999999999999999999999999"
, ist das Verhalten undefiniert (obwohl sich die meisten oder alle Implementierungen ordnungsgemäß verhalten sollten). Ich gehe davon aus9999999999999999999999999 > INT_MAX
.Ich verwende eine
std::string::compare
in Dienstprogramm eingeschlossene Methode wie folgt:quelle
Warum nicht gnu getopts verwenden? Hier ist ein grundlegendes Beispiel (ohne Sicherheitsüberprüfungen):
Für den folgenden Befehl:
Sie erhalten
quelle
Wenn Sie C ++ 11-Kompatibilität benötigen und Boost nicht verwenden können, finden Sie hier ein Boost-kompatibles Drop-In mit einem Anwendungsbeispiel:
quelle
Sie können auch verwenden
strstr
:aber ich denke, es ist nur für kurze Strings gut, weil es den gesamten String durchlaufen muss, wenn der String nicht mit 'substr' beginnt.
quelle
Ok, warum die komplizierte Verwendung von Bibliotheken und Sachen? C ++ String-Objekte überladen den Operator [], sodass Sie nur Zeichen vergleichen können. Wie ich es gerade getan habe, weil ich alle Dateien in einem Verzeichnis auflisten und unsichtbare Dateien und die .. und ignorieren möchte. Pseudodateien.
So einfach ist das.
quelle
quelle
Mit C ++ 11 oder höher können Sie
find()
und verwendenfind_first_of()
Beispiel mit find, um ein einzelnes Zeichen zu finden:
Beispiel mit find, um eine vollständige Zeichenfolge zu finden und ab Position 5:
Beispiel mit dem
find_first_of()
und nur dem ersten Zeichen, um nur am Anfang zu suchen:Viel Glück!
quelle
Da C ++ 11
std::regex_search
auch verwendet werden kann, um noch komplexere Ausdrücke abzugleichen. Das folgende Beispiel behandelt auch schwebende Zahlen durchstd::stof
und eine nachfolgende Umwandlung inint
.Die
parseInt
unten gezeigte Methode kann jedoch einestd::invalid_argument
Ausnahme auslösen, wenn das Präfix nicht übereinstimmt. Dies kann je nach Anwendung leicht angepasst werden:Die Art der Magie des Regex-Musters wird in der folgenden Antwort ausführlich beschrieben .
BEARBEITEN: Die vorherige Antwort hat die Konvertierung in eine Ganzzahl nicht durchgeführt.
quelle
Ab C ++ 20 können Sie die
starts_with
Methode verwenden.quelle
Dies ist völlig ungetestet. Das Prinzip ist das gleiche wie beim Python. Benötigt Boost.StringAlgo und Boost.LexicalCast.
Überprüfen Sie, ob die Zeichenfolge mit der anderen Zeichenfolge beginnt, und rufen Sie dann die Teilzeichenfolge ('Slice') der ersten Zeichenfolge ab und konvertieren Sie sie mit lexikalischer Umwandlung.
quelle