Jak zaimplementować następujące (pseudokod Python) w C ++?
if argv[1].startswith('--foo='):
foo_value = int(argv[1][len('--foo='):])
(Na przykład, jeśli argv[1]
jest --foo=98
, to foo_value
jest 98
.)
Aktualizacja: waham się, czy zagłębić się w Boost, ponieważ chcę tylko dokonać niewielkiej zmiany w prostym, małym narzędziu wiersza poleceń (wolałbym nie uczyć się, jak łączyć się i używać Boost dla drobnej zmiana).
Odpowiedzi:
Użyj przeciążenia,
rfind
któregopos
parametr ma parametr:Kto potrzebuje czegoś jeszcze? Pure STL!
Wielu błędnie odczytało to, co oznacza „przeszukuj wstecz cały ciąg szukając prefiksu”. To dałoby zły wynik (np.
string("tititito").rfind("titi")
Zwraca 2, więc w porównaniu z== 0
zwróciłoby fałsz) i byłoby nieefektywne (przeglądanie całego łańcucha zamiast samego początku). Ale nie robi tego, ponieważ przekazujepos
parametr as0
, co ogranicza wyszukiwanie do dopasowania tylko w tej pozycji lub wcześniej . Na przykład:źródło
find
będzie wynosić tylko zero, jeślititi
jest na początku łańcucha. Jeśli zostanie znaleziony gdzie indziej, otrzymasz niezerową wartość zwracaną, a jeśli nie zostanie znaleziony, otrzymasznpos
również niezerową. Zakładając, że mam rację, wolałbym tę odpowiedź, ponieważ nie muszę wnosić żadnych niestandardowych rzeczy (tak, wiem, że Boost jest wszędzie, po prostu wolę podstawowe biblioteki C ++ do takich prostych rzeczy).titi
, ale brakuje części konwersji.rfind()
które nie przyjmujepos
parametru. Jeśli użyjesz przeciążenia, które pobierapos
parametr, nie będzie przeszukiwał całego łańcucha, tylko tę pozycję i wcześniej. (Tak jak zwykłyfind()
zpos
parametrem wygląda tylko w tej pozycji lub później.) Więc jeśli zdaszpos == 0
, jak pokazano w tej odpowiedzi, to dosłownie rozważy tylko dopasowania dla tej jednej pozycji. To już wyjaśniało zarówno odpowiedź, jak i komentarze.Zrobiłbyś to w ten sposób:
Poszukiwanie biblioteki takiej jak Boost.ProgramOptions, która zrobi to za Ciebie, jest również dobrym pomysłem.
źródło
atoi("123xyz")
zwraca123
, podczas gdy Pythonint("123xyz")
zgłasza wyjątek.atoi
sięstrtol
lubstrtoll
, co pozwala nam wykryć warunki błędach w wartości wejściowej.rfind
które zależy od optymalizacji do pracy.Dla kompletności wspomnę o sposobie C:
(pierwotnie opublikowane przez Yaseen Rauf tutaj , dodano znaczniki)
Dla porównania bez rozróżniania wielkości liter, użyj
strnicmp
zamiaststrncmp
.Jest to sposób C, aby to zrobić, dla ciągów C ++ możesz użyć tej samej funkcji, jak poniżej:
źródło
memcmp()
Jeśli już używasz wzmocnienia, możesz to zrobić za pomocą algorytmów ciągu wzmocnionego + wzmocnienia rzutowania leksykalnego:
Takie podejście, podobnie jak wiele innych podanych tutaj odpowiedzi, jest odpowiednie w przypadku bardzo prostych zadań, ale na dłuższą metę zwykle lepiej jest korzystać z biblioteki parsowania wiersza poleceń. Boost ma jeden ( Boost.Program_options ), co może mieć sens, jeśli już używasz .
W przeciwnym razie poszukiwanie „parsera wiersza poleceń c ++” da szereg opcji.
źródło
Kod, którego używam:
źródło
substr
prowadzi do niepotrzebnego kopiowania.str.compare(start, count, substr)
Metoda stosowana w odpowiedzi Thomas jest bardziej efektywny. Odpowiedź razvanco13 ma inną metodę, która pozwala uniknąć kopiowania za pomocąstd::equal
.Thomas uses atoi which is only for windows
Huh?atoi
jest standardową funkcją biblioteki C od ... kiedykolwiek. W rzeczywistości,atoi
jest złe-nie dlatego, że jest Windows specific- ale dlatego, że (1) C, nie C ++, oraz (2) przestarzałe nawet w C (należy używaćstrtol
lub jednego z innych, powiązanych funkcji. Ponieważatoi
ma brak obsługi błędów. Ale i tak to tylko w C).Nikt jeszcze nie używał funkcji algorytmu / niedopasowania STL . Jeśli to zwraca wartość true, prefiks jest prefiksem „toCheck”:
Pełny przykładowy program:
Edytować:
Jak sugeruje @James T. Huggett, std :: równe lepiej pasuje do pytania: czy A jest prefiksem B? i jest nieco krótszy kod:
Pełny przykładowy program:
źródło
std::equal
ciągów ma tę wadę, że nie wykrywa końca łańcucha, więc musisz ręcznie sprawdzić, czy prefiks jest krótszy niż cały ciąg. (Jak poprawnie zrobiono w przykładowym progu, ale pominięto w powyższejBiorąc pod uwagę, że oba ciągi -
argv[1]
i"--foo"
- są ciągami C, odpowiedź @ FelixDombek jest praktycznym najlepszym rozwiązaniem.Widząc inne odpowiedzi, pomyślałem jednak, że warto zauważyć, że jeśli twój tekst jest już dostępny jako
std::string
, to istnieje proste, maksymalnie efektywne rozwiązanie, które nie zostało wspomniane do tej pory:A jeśli foo jest już ciągiem:
źródło
rfind(x, 0) == 0
należy naprawdę zdefiniować w standardzie jakostarts_with
rfind()
(zamiaststartswith()
) jest bardzo nieefektywny - szuka do końca łańcucha.Z C ++ 17 możesz korzystać
std::basic_string_view
z C ++ 20std::basic_string::starts_with
lubstd::basic_string_view::starts_with
.Zaletą
std::string_view
w porównaniu dostd::string
- w odniesieniu do zarządzania pamięcią - jest to, że trzyma wskaźnik do „łańcucha” (ciągłej sekwencji obiektów podobnych do znaków) i zna jego rozmiar. Przykład bez przenoszenia / kopiowania ciągów źródłowych, aby uzyskać wartość całkowitą:źródło
std::atoi
jest całkowicie w porządku. Zgłasza wyjątki od złych danych wejściowych (które są obsługiwane w tym kodzie). Czy miałeś na myśli coś innego?atoi
z<cstdlib>
? Dokumentacja mówi „nigdy nie rzuca wyjątki”.atoi
zamiaststd::atoi
. Pierwszy jest niebezpieczny w użyciu, a drugi jest w porządku. Używam tego ostatniego w kodzie tutaj.std::atoi
rzeczywiście rzuca wyjątek, powołując się na odpowiednie odniesienie. Dopóki tego nie zrobisz, nie wierzę ci, ponieważ byłoby to bardzo mylące, mając oba::atoi
istd::atoi
działając w zupełnie inny sposób.std::atoi
zamiast tego zastosowano przeoczeniestd::stoi
. Naprawiłem to.źródło
if (one-liner)
Przy użyciu STL może to wyglądać następująco:
źródło
if (prefix.size()<=arg.size() && std::equal(...))
.Ryzykując podpalenie za użycie konstruktów C, uważam, że ten
sscanf
przykład jest bardziej elegancki niż większość rozwiązań wspomagających. I nie musisz się martwić o powiązanie, jeśli biegasz w dowolnym miejscu, które ma interpreter Pythona!Oto kilka przykładowych danych wyjściowych, które pokazują, że rozwiązanie obsługuje początkowe / końcowe śmieci tak poprawnie jak równoważny kod Pythona i bardziej poprawnie niż cokolwiek innego
atoi
(co błędnie zignoruje nieliczbowy przyrostek).źródło
argv[i]
tak"--foo=9999999999999999999999999"
, zachowanie jest niezdefiniowane (chociaż większość lub wszystkie implementacje powinny zachowywać się rozsądnie). Jestem przy założeniu9999999999999999999999999 > INT_MAX
.Używam
std::string::compare
owiniętej metody użyteczności, jak poniżej:źródło
Dlaczego nie skorzystać z GNU Getopts? Oto podstawowy przykład (bez kontroli bezpieczeństwa):
Dla następującego polecenia:
Dostaniesz
źródło
Jeśli potrzebujesz kompatybilności z C ++ 11 i nie możesz użyć boosta, oto drop-in kompatybilny z boostem z przykładem użycia:
źródło
Możesz także użyć
strstr
:ale myślę, że jest to dobre tylko dla krótkich łańcuchów, ponieważ musi on zapętlać cały łańcuch, gdy tak naprawdę łańcuch nie zaczyna się od „substr”.
źródło
Ok, dlaczego skomplikowane korzystanie z bibliotek i innych rzeczy? Obiekty łańcucha C ++ przeciążają operator [], więc możesz po prostu porównywać znaki. Podobnie jak to, co właśnie zrobiłem, ponieważ chcę wyświetlić listę wszystkich plików w katalogu i zignorować pliki niewidoczne oraz ... i. pseudofile.
To takie proste..
źródło
źródło
W C ++ 11 lub nowszym możesz używać
find()
ifind_first_of()
Przykład użycia find do znalezienia pojedynczego znaku:
Przykład użycia znajdź, aby znaleźć pełny ciąg i zaczynając od pozycji 5:
Przykład użycia
find_first_of()
i tylko pierwszego znaku, aby wyszukać tylko na początku:Powodzenia!
źródło
Ponieważ C ++ 11
std::regex_search
może również służyć do zapewniania jeszcze bardziej złożonego dopasowania wyrażeń. Poniższy przykład obsługuje również liczby zmiennoprzecinkowestd::stof
i kolejne rzutowania naint
.Jednak
parseInt
metoda pokazana poniżej może zgłosićstd::invalid_argument
wyjątek, jeśli przedrostek nie zostanie dopasowany; można to łatwo dostosować w zależności od aplikacji:Rodzaj magii wzoru regularnego jest szczegółowo opisany w następującej odpowiedzi .
EDYCJA: poprzednia odpowiedź nie przeprowadziła konwersji na liczbę całkowitą.
źródło
Począwszy od C ++ 20, możesz użyć tej
starts_with
metody.źródło
Jest to całkowicie niesprawdzone. Zasada jest taka sama jak w języku Python. Wymaga Boost.StringAlgo i Boost.LexicalCast.
Sprawdź, czy łańcuch zaczyna się od drugiego łańcucha, a następnie pobierz podłańcuch („plasterek”) pierwszego łańcucha i przekonwertuj go za pomocą rzutowania leksykalnego.
źródło