Powiedzmy, że mam dwie struny
String s1 = "AbBaCca";
String s2 = "bac";
Chcę wykonać zwrot czeku, który s2
jest zawarty w s1
. Mogę to zrobić za pomocą:
return s1.contains(s2);
Jestem pewien, że contains()
rozróżniana jest wielkość liter, jednak nie mogę tego ustalić na podstawie lektury dokumentacji. Jeśli tak, to sądzę, że moją najlepszą metodą byłoby coś takiego:
return s1.toLowerCase().contains(s2.toLowerCase());
Pomijając wszystko, czy istnieje inny (być może lepszy) sposób na osiągnięcie tego bez dbania o rozróżnianie wielkości liter?
Odpowiedzi:
Tak, zawiera rozróżnia małe i wielkie litery. Możesz użyć java.util.regex.Pattern z flagą CASE_INSENSITIVE do dopasowywania bez rozróżniania wielkości liter:
EDYCJA: Jeśli s2 zawiera regexowe znaki specjalne (których jest wiele), ważne jest, aby zacytować je jako pierwsze. Poprawiłem odpowiedź, ponieważ ludzie widzą ją po raz pierwszy, ale głosujcie Mattowi Quailowi, odkąd to zauważył.
źródło
Pattern.CASE_INSENSITIVE
, działa to tylko dla znaków ASCII (tzn. „Ę” nie pasuje do „ä”). AbyUNICODE_CASE
to osiągnąć, należy dodatkowo określić flagę.Pattern
bardziej wydajne niżs1.toLowerCase().contains(s2.toLowerCase())
?Pattern.compile(Pattern.quote(needle), Pattern.CASE_INSENSITIVE).matcher(haystack).find()
Jednym z problemów z odpowiedzią Dave'a L. jest to, że s2 zawiera znaczniki regularne, takie jak
\d
itp.Chcesz wywołać Pattern.quote () na s2:
źródło
toLowerCase().contains()
jest szybszy. Przeprowadziłem analizę prędkości, zobacz moją odpowiedź dla wyników: stackoverflow.com/a/25379180/1705598Pattern.UNICODE_CASE
flagę. Czy możesz to potwierdzić?Możesz użyć
Biblioteka Apache Commons jest bardzo przydatna do tego typu rzeczy. A ten konkretny może być lepszy niż wyrażenia regularne, ponieważ wyrażenie regularne jest zawsze drogie pod względem wydajności.
źródło
String.regionMatches
, który wykorzystuje konwersje znakowe, więc nie. PonadtocontainsIgnoreCase("ß", "ss")
zwraca -1, co jest niepoprawne w każdym locale (niemiecki „sharp s”Szybsza implementacja: wykorzystanie
String.regionMatches()
Korzystanie z wyrażenia regularnego może być stosunkowo wolne. To (powolne) nie ma znaczenia, jeśli chcesz tylko sprawdzić w jednym przypadku. Ale jeśli masz tablicę lub kolekcję tysięcy lub setek tysięcy ciągów, rzeczy mogą być dość powolne.
Przedstawione poniżej rozwiązanie nie używa wyrażeń regularnych ani
toLowerCase()
(co jest również powolne, ponieważ tworzy kolejne ciągi znaków i po prostu je wyrzuca po sprawdzeniu).Rozwiązanie opiera się na metodzie String.regionMatches () , która wydaje się nieznana. Sprawdza, czy 2
String
regiony pasują do siebie, ale ważne jest to, że ma również przeciążenie przydatnymignoreCase
parametrem.Analiza prędkości
Ta analiza prędkości nie oznacza nauki o rakietach, tylko przybliżony obraz szybkości różnych metod.
Porównuję 5 metod.
String.contains()
.String.contains()
z wstępnie buforowanym podciągiem, małymi literami. To rozwiązanie nie jest już tak elastyczne, ponieważ testuje podciąg predefiend.Pattern.compile().matcher().find()
...)Pattern
. To rozwiązanie nie jest już tak elastyczne, ponieważ testuje predefiniowany podciąg.Wyniki (wywołując metodę 10 milionów razy):
Pattern
: 1845 msWyniki w tabeli:
Nasza metoda jest czterokrotnie szybsza w porównaniu do mniejszych liter i używania
contains()
, 10 razy szybsza w porównaniu do używania wyrażeń regularnych, a także 3 razy szybsza, nawet jeśliPattern
jest wstępnie buforowana (i traci elastyczność sprawdzania dowolnego podciągu).Kod testu analitycznego
Jeśli interesuje Cię sposób przeprowadzenia analizy, oto kompletna aplikacja do uruchomienia:
źródło
ß
(niemieckie ostre S; wielkie litery doSS
), a także dla niektórych innych postaci (patrz źródłoString.regionMatches
, które próbuje obu konwersji).StringUtils.containsIgnoreCase()
jest to, że zarówno moje rozwiązanie, jak i Apache używająregionMatches()
metody (w cyklu), ale nawet to nie jest to samo, co wywołujęString.regionMatches()
i wywołuje ApacheCharSequenceUtils.regionMatches()
.CharSequenceUtils.regionMatches
właśnie dzwoniString.regionMatches
. W każdym razie, moim celem było podanie informacji, że jeśli ktoś już korzysta z StringUtils lib, może po prostu to nazwać, ponieważ wydaje się, że jest to skuteczny sposób, jak to udowodnisz za pomocą testu porównawczego. Gdybym nie korzystał z biblioteki Apache lib, zdecydowanieProstszym sposobem na zrobienie tego (bez obawy o dopasowanie wzorca) byłoby przekonwertowanie obu
String
s na małe litery:źródło
Tak, można to osiągnąć:
Ten kod zwróci ciąg „PRAWDA!” ponieważ okazało się, że twoje postacie były zamknięte.
źródło
s2
. Nie mówiąc o takich szczegółach, że ten się nie kompiluje, a jeśli tak, zwróci ciąg.Możesz używać wyrażeń regularnych i działa:
źródło
Oto kilka przyjaznych dla Unicode, które możesz zrobić, jeśli włączysz ICU4j. Wydaje mi się, że „ignoruj wielkość liter” jest wątpliwa w przypadku nazw metod, ponieważ chociaż pierwotne porównania siły ignorują wielkość liter, opisuje się je jako zależne od ustawień regionalnych. Ale miejmy nadzieję, że zależy to od lokalizacji w sposób, jakiego mógłby oczekiwać użytkownik.
źródło
Zrobiłem test, szukając dopasowania łańcucha bez rozróżniania wielkości liter. Mam wektor 150 000 obiektów z ciągiem jako jednym polem i chciałem znaleźć podzbiór pasujący do ciągu. Wypróbowałem trzy metody:
Konwertuj wszystko na małe litery
Użyj metody String Match ()
Używaj wyrażeń regularnych
Wyniki pomiaru czasu są następujące:
Brak próby dopasowania: 20 ms
Aby obniżyć dopasowanie: 182 ms
Ciągi znaków: 278 ms
Wyrażenie regularne: 65 ms
Wyrażenie regularne wydaje się najszybsze w tym przypadku użycia.
źródło
Istnieje prosty, zwięzły sposób, używając flagi wyrażenia regularnego (bez rozróżniania wielkości liter {i}):
źródło
Nie jestem pewien, jakie jest twoje główne pytanie, ale tak, w .contains rozróżniana jest wielkość liter.
źródło
Zasadniczo jest to metoda, która wymaga dwóch ciągów. Powinna to być wersja rozróżniająca wielkość liter (). Korzystając z metody zawiera, chcesz sprawdzić, czy jeden ciąg znaków jest zawarty w drugim.
Ta metoda pobiera ciąg „sub” i sprawdza, czy jest równy podciągowi ciągu kontenera o długości równej „sub”. Jeśli spojrzysz na
for
pętlę, zobaczysz, że iteruje się w podciągach (które są długością „sub”) nad ciągiem kontenera.Każda iteracja sprawdza, czy podłańcuch łańcucha kontenera jest
equalsIgnoreCase
podrzędny.źródło
Jeśli musisz wyszukać ciąg ASCII w innym ciągu ASCII, takim jak adres URL , moje rozwiązanie będzie lepsze. Testowałem metodę icza i moją pod kątem prędkości i oto wyniki:
Kod:
źródło
źródło
źródło
Możemy używać strumienia z anyMatch i zawiera Java 8
źródło
lub możesz zastosować proste podejście i po prostu przekonwertować wielkość ciągu na wielkość ciągu, a następnie użyć metody
źródło
źródło
Możesz po prostu zrobić coś takiego:
źródło