2011-03-29 12 views
48

Chciałbym porównać dwie zmienne, aby sprawdzić, czy są one takie same, ale chcę, aby to porównanie było bez rozróżniania wielkości liter.Nieczułe na wielkość liter porównywanie ciągów znaków

Na przykład, byłoby to wielkość liter:

if($var1 == $var2){ 
    ... 
} 

Ale chcę to być przypadek nieczuły, jak bym podejść do tego?

+1

ściśle rzecz biorąc, jeśli nie może być przypadek (w) wrażliwe, jak to działa tylko wartości logiczne. Operatorem porównania jest '==' jeden. –

Odpowiedz

82

Jest to dość proste; wystarczy wywołać strtolower() dla obu zmiennych.

Jeśli chcesz zajmować się zestawami znaków Unicode lub międzynarodowych, możesz użyć mb_strtolower().

Należy pamiętać, że inne odpowiedzi sugerują, że za pomocą strcasecmp() — funkcjonować nie obsługuje znaki wielobajtowe, więc wyników dla dowolnego ciągu znaków UTF-8 będzie podrobiony.

+0

Dzięki, czy przypadkiem wiesz, w jaki sposób mogę zrobić rozróżnianie wielkości liter WHERE w mysql_query()? –

+1

Ogólnie uważam, że porównywanie ciągów MySQL * nie uwzględnia wielkości liter. Oznacza to, że "A" = "a" "jest prawdziwe. Odsyłacz: http://dev.mysql.com/doc/refman/5.0/en/case-sensitivity.html – syrion

+0

To bardzo dziwne, ponieważ nie to robi dla mnie. Ustawiłem zestawienie z latin1_swedish_ci. –

2
if(strtolower($var1) == strtolower($var2)){ 
} 
0

Dlaczego nie:

if(strtolower($var1) == strtolower($var2)){ 
} 
57

strcasecmp() zwraca 0 jeśli struny są takie same (oprócz wariantów przypadku), dzięki czemu można używać:

if (strcasecmp($var1, $var2) == 0) { 
} 
+3

Just pamiętaj, aby przetestować dla == 0; jest to sprzeczne z intuicją, ponieważ bardzo kuszące jest napisanie "if (strcasecmp ($ var1, $ var2)) {...", ale w tym przypadku 0 oznacza raczej równy niż fałszywy-nutyqual, jak to często bywa. – Chirael

+3

'strcasecmp()' nie zajmuje się znakami wielobajtowymi, więc nie radzi sobie z Unikodem. – syrion

8

Jeśli łańcuch jest w jednym kodowanie bajtów, to proste:

if(strtolower($var1) === strtolower($var2)) 

Jeśli łańcuch jest UTF-8, trzeba wziąć pod uwagę złożoność Unicode: do małymi literami, a do górnej -case nie są funkcjami bijective, tzn. jeśli masz małe litery, przekształcasz je na wielkie litery i przekształcasz je z powrotem na małe litery, możesz nie skończyć z tym samym kodem (i to samo obowiązuje, jeśli zaczynasz od wielka litera).

E.g.

  • "I" (Latin Capital Letter I with Dot Above, U+0130) jest górną liter, z "ja" (Latin Small Letter I, U+0069) w swoim dolnym przypadku wariantu - i "I" 's górnego wariantu przypadek jest "ja" (Latin Capital Letter I, U+0049).
  • "I" (Latin Small Letter Dotless I, U+0131) jest niższa postać przypadek, z "I" (Latin Capital Letter I, U+0049) jako jego górnej wariantu przypadek - i "ja" jest niższy wariant sprawa jest "ja" (Latin Small Letter I, U+0069)

Tak więc mb_strtolower('ı') === mb_strtolower('i') zwraca wartość false, nawet jeśli mają one taki sam duży znak.Jeśli naprawdę chcesz funkcję porównywania ciąg bez uwzględniania wielkości liter, trzeba porównać do górnej obudowy oraz dolnej wersji obudowy:

if(mb_strtolower($string1) === mb_strtolower($string2) 
    || mb_strtoupper($string1) === mb_strtoupper($string2)) 

Zabrakło mi kwerendy w bazie danych Unicode z https://codepoints.net (https://dumps.codepoints.net) i I” ve znalazłem 180 punktów kodowych, dla których znalazłem inny znak podczas pisania dużej litery pisanej małymi literami, oraz 8 punktów kodowych, dla których znalazłem inny znak podczas robienia wielkich liter pisanych dużymi literami:

Ale jest gorzej: ten sam zbiór grafem widziany przez użytkownika może mieć wiele sposobów kodowania go: " "może być reprezentowany jako Latin Small Letter a with Diaeresis (U+00E4) lub jako Latin Small Letter A (U+0061) i Combining Diaeresis (U+0308) - a jeśli porównasz je na poziomie bajtów, to nie zwróci true!

Ale jest na to rozwiązanie w Unicode: Normalization! Istnieją cztery różne formy: NFC, NFD, NFKC, NFKD. Dla porównania łańcuchów, NFC i NFD są równoważne, a NFKC i NFKD są równoważne. Wziąłbym NFKC, ponieważ jest krótszy niż NFKD, a "ff" (Latin Small Ligature ff, U+FB00) zostanie przekształcony na dwa zwykłe "f" (ale 2⁵ również zostanie rozszerzone do 25 ...).

Funkcja wynikające staje:

function mb_is_string_equal_ci($string1, $string2) { 
    $string1_normalized = Normalizer::normalize($string1, Normalizer::FORM_KC); 
    $string2_normalized = Normalizer::normalize($string2, Normalizer::FORM_KC); 
    return mb_strtolower($string1_normalized) === mb_strtolower($string2_normalized) 
      || mb_strtoupper($string1_normalized) === mb_strtoupper($string2_normalized); 
} 

Uwaga:

  • trzeba pakiet intl dla Normalizer
  • należy zoptymalizować tę funkcję najpierw sprawdzenie, czy są one po prostu równa ^^
  • możesz użyć NFC zamiast NFKC, ponieważ NFKC usuwa zbyt wiele rozróżnień formatowania dla R Twój smak
  • musisz sam zdecydować, czy naprawdę potrzebują tej złożoności lub jeśli wolisz prostszy wariant tej funkcji
Powiązane problemy