Ostrzeżenie: większość odpowiedzi tutaj nie jest wiarygodna w kodowaniu wielobajtowym, takim jak UTF-8.
Álvaro González
W związku z powyższym komentarzem możesz upewnić się, że używasz najnowszej wersji (na dzień dzisiejszy 5.4 ). Warto zauważyć, że opensWith () został zoptymalizowany pod kątem dużych łańcuchów stogów siana.
+1 To jest czystsze niż zaakceptowana odpowiedź. Ponadto $lengthnie jest potrzebny w ostatnim wierszu pliku endsWith().
za dużo php
13
Powiedziałbym, że końcoweWith ('foo', '') == false to poprawne zachowanie. Ponieważ foo nie kończy się niczym. „Foo” kończy się na „o”, „oo” i „Foo”.
MrHus
125
Końcówki można napisać znacznie krócej:return substr($haystack, -strlen($needle))===$needle;
Rok Kralj
12
Można uniknąć ifcałkowicie przekazując $lengthjako trzeci parametr substr: return (substr($haystack, -$length, $length);. To rozwiązuje przypadek $length == 0zwracając pusty ciąg, a nie całość $haystack.
mxxk
20
@MrHus Polecam korzystanie z wielobajtowych bezpiecznych funkcji, np. Mb_strlen i mb_substr
19Gerhard85 25.04.16
1024
Możesz użyć substr_comparefunkcji, aby sprawdzić początek i koniec:
function startsWith($haystack, $needle){return substr_compare($haystack, $needle,0, strlen($needle))===0;}function endsWith($haystack, $needle){return substr_compare($haystack, $needle,-strlen($needle))===0;}
To powinno być jedno z najszybszych rozwiązań na PHP 7 ( skrypt porównawczy ). Testowany na stogach siana o pojemności 8 KB, różnych długościach igieł oraz pełnych, częściowych i niepasujących skrzyniach. strncmpjest odrobinę szybszy na początku, ale nie może sprawdzić końca.
Pamiętaj, że komentarze @DavidWallace i @FrancescoMM dotyczą starszej wersji tej odpowiedzi. Obecna odpowiedź wykorzystuje, strrposktóra (powinna) zawieść natychmiast, jeśli igła nie pasuje do początku stogu siana.
Salman A
2
Nie rozumiem Na podstawie php.net/manual/en/function.strrpos.php : „Jeśli wartość jest ujemna, wyszukiwanie rozpocznie się od tylu znaków od końca łańcucha, szukając wstecz.” To wydaje się wskazywać, że zaczynamy od znaku 0 (z powodu -strlength($haystack)) i szukamy stamtąd wstecz ? Czy to nie znaczy, że niczego nie przeszukujesz? Nie rozumiem też !== falseczęści tego. Zgaduję, że opiera się to na dziwactwie PHP, w którym niektóre wartości są „prawdziwe”, a inne „fałszywe”, ale jak to działa w tym przypadku?
Welbog
3
@Welbog: na przykład haystack = xxxyyyigła = yyyi korzystanie strrposz wyszukiwania rozpoczyna się od pierwszego x. Teraz nie mamy udany mecz tutaj (znaleziono x zamiast y) i nie możemy już iść do tyłu (jesteśmy na początku łańcucha) poszukiwanie nie natychmiast . O użyciu !== false- strrposw powyższym przykładzie zwróci 0 lub false, a nie inną wartość. Podobnie strposw powyższym przykładzie może zostać zwrócona $temp(oczekiwana pozycja) lub fałszywa. Poszedłem z !== falsekonsekwencją, ale można było użyć odpowiednio === 0i === $tempfunkcji.
Salman,
8
@spoo już ustalono, że strpos === 0 jest okropnym rozwiązaniem, jeśli stóg siana jest duży, a igła nie istnieje.
strncmp_startswith2:40.2 ms
strncmp_startswith:42.9 ms
substr_compare_startswith:44.5 ms
substr_startswith:48.4 ms
strpos_startswith:138.7 ms
preg_match_startswith:13,152.4 ms
Wyniki (PHP 5.3.29)
(Posortowane od najszybszego do najwolniejszego)
strncmp_startswith2:477.9 ms
strpos_startswith:522.1 ms
strncmp_startswith:617.1 ms
substr_compare_startswith:706.7 ms
substr_startswith:756.8 ms
preg_match_startswith:10,200.0 ms
Jeśli łańcuchy nie są puste, jak w twoich testach, jest to w rzeczywistości (20-30%) szybsze: function startswith5b($haystack, $needle) {return ($haystack{0}==$needle{0})?strncmp($haystack, $needle, strlen($needle)) === 0:FALSE;}dodałem odpowiedź poniżej.
FrancescoMM,
3
@Jronny Ponieważ 110 to mniej niż 133 ... ??
mpen
2
Cholera, nie wiem, co wtedy przyszło mi do głowy. Chyba brak snu.
Jronny,
1
@mpen, w ogóle nie zauważyłem słonia :(
Visman
1
Te testy nie są dobre w testowaniu wydajności. To, co robisz, to używanie losowego łańcucha jako igły. W 99,99% przypadków nie będzie zgodności. Większość funkcji zostanie zakończona po dopasowaniu pierwszego bajtu. Co z przypadkami znalezienia dopasowania? Która funkcja zajmuje najmniej czasu, aby zakończyć udany mecz? Co z przypadkami, w których 99% igły pasuje, ale nie ostatnich kilku bajtów? Która funkcja zajmuje najmniej czasu, aby stwierdzić brak dopasowania?
Salman,
137
Wszystkie odpowiedzi do tej pory wydaje się robić mnóstwo niepotrzebnej pracy strlen calculations, string allocations (substr)itp 'strpos'i 'stripos'zwracają indeks pierwszego wystąpienia $needlew $haystack:
endsWith()funkcja ma błąd. Pierwszą linią powinien być (bez -1): $expectedPosition = strlen($haystack) - strlen($needle);
Enrico Detoma
6
Funkcja strlen () nie jest niepotrzebna. W przypadku, gdy łańcuch nie zaczyna się od podanej igły, Twój kod niepotrzebnie skanuje cały stóg siana.
AppleGrew
5
@ Oznacz tak, sprawdzanie tylko początku jest DUŻO szybsze, szczególnie jeśli robisz coś takiego jak sprawdzanie typów MIME (lub dowolnego innego miejsca, w którym łańcuch musi być duży)
chacham15
2
@mark Zrobiłem kilka testów porównawczych ze stosem siana 1000 znaków i igłą 10 lub 800 znaków, a strpos było o 30% szybsze. Wykonaj swoje testy porównawcze, zanim stwierdzisz, że coś jest szybsze, czy nie ...
strtolower nie jest najlepszym sposobem na rozróżnianie wielkości liter. W niektórych lokalizacjach obudowa jest bardziej złożona niż tylko górna i dolna.
Sander Rijken
8
Widzę narzekanie i brak rozwiązania ... Jeśli chcesz powiedzieć, że jest źle, powinieneś podać przykład, jak powinno być.
KdgDev
2
@WebDevHobo: dlatego dodałem odpowiedź na dzień przed Twoim komentarzem. W przypadku twojego kodu strcasecmp rzeczywiście był właściwą rzeczą.
Sander Rijken,
29
Wyrażenia regularne działają powyżej, ale z innymi poprawkami również sugerowanymi powyżej:
w php dla operacji na łańcuchach kolejność parametrów to $ stóg siana, $ igła. funkcje te działają wstecz i działają jak funkcje tablicowe, w których kolejność to w rzeczywistości $ igła, $ stóg siana.
Andy
29
To pytanie ma już wiele odpowiedzi, ale w niektórych przypadkach możesz zadowolić się czymś prostszym niż wszystkie. Jeśli ciąg, którego szukasz, jest znany (zakodowany na stałe), możesz używać wyrażeń regularnych bez cudzysłowu itp.
Sprawdź, czy ciąg zaczyna się od „ABC”:
preg_match('/^ABC/', $myString);// "^" here means beginning of string
kończy się na „ABC”:
preg_match('/ABC$/', $myString);// "$" here means end of string
W moim prostym przypadku chciałem sprawdzić, czy ciąg kończy się ukośnikiem:
preg_match('#/$#', $myPath);// Use "#" as delimiter instead of escaping slash
Zaleta: ponieważ jest bardzo krótka i prosta, nie trzeba definiować funkcji (takich jak endsWith()), jak pokazano powyżej.
Ale znowu - to nie jest rozwiązanie dla każdego przypadku, tylko ten bardzo konkretny.
nie musisz na stałe kodować łańcucha. Wyrażenie regularne może być dynamiczne.
Ryan
2
@ sama prawda, ale jeśli ciąg nie jest zakodowany na stałe, musisz go uciec. Obecnie na to pytanie udzielono 2 odpowiedzi. Jest to łatwe, ale nieco komplikuje kod. Chodzi mi więc o to, że w bardzo prostych przypadkach, w których możliwe jest kodowanie na stałe, możesz zachować prostotę.
noamtm
1
Nie musisz także uciekać przed ukośnikiem, możesz owinąć wyrażenie regularne inną postacią, na przykład @, aby ukośnik ( /) nie musiał uciekać. Zobacz przykład 3 tutaj: php.net/manual/en/function.preg-match.php .
+1 Działa od PHP5.1 i najlepszej odpowiedzi IMHO. Ale endsWidthpowinien zrobić return $needle==='' || substr_compare(... więc działa zgodnie z oczekiwaniami -strlen($needle)===0, a bez poprawki endsWith('a','')zwracafalse
Tino
@Tino Dzięki ... Wydaje mi się, że to błąd substr_compare(), więc dodałem PR, aby to naprawić :)
Ja 21ck
3
Wywołanie endsWith('', 'foo')wyzwala Ostrzeżenie: „substr_compare (): Pozycja początkowa nie może przekroczyć początkowej długości łańcucha”. Może to kolejny błąd substr_compare(), ale aby tego uniknąć, potrzebujesz wstępnej kontroli, takiej jak ... || (strlen($needle) <= strlen($haystack) && substr_compare(...) === 0);
gx_
@gx_ Nie trzeba zwalniać z większą ilością kodu. Wystarczy użyć return $needle === '' || @substr_compare(..., aby ukryć to ostrzeżenie.
Tino,
17
Najszybsze rozwiązanie Rozwiązanie ():
# Checks if a string ends in a stringfunction endsWith($haystack, $needle){return substr($haystack,-strlen($needle))===$needle;}
+1 za poświęcenie czasu na porównanie różnych rozwiązań i ich porównanie! powinieneś również wspomnieć, jakiej wersji PHP użyłeś, ponieważ optymalizacje są dokonywane wraz z rozwojem języka! Widziałem radykalne usprawnienia funkcji porównywania ciągów z jednej wersji PHP do drugiej :)
Christophe Deliens
1
echo @ChristopheDeliens i jego prośba o dostarczenie wersji PHP. Uruchomiłem test na 7.3.2 i uzyskałem podobne wyniki FWIW.
Jeff
16
Zdaję sobie sprawę, że zostało to zakończone, ale możesz chcieć spojrzeć na strncmp, ponieważ pozwala on ustawić długość łańcucha do porównania, więc:
function startsWith($haystack, $needle, $case=true){if($case)return strncasecmp($haystack, $needle, strlen($needle))==0;elsereturn strncmp($haystack, $needle, strlen($needle))==0;}
@Mark - możesz zobaczyć zaakceptowaną odpowiedź, ale wolę używać strncmp głównie dlatego, że uważam, że jest bezpieczniejszy.
James Black
Mam na myśli konkretnie strncmp. Nie można określić przesunięcia. Oznaczałoby to, że twoje cele z funkcją musiałyby całkowicie użyć innej metody.
mpen
@Mark - Dla EndWith Chciałbym po prostu użyć strrpos ( php.net/manual/en/function.strrpos.php ), ale ogólnie rzecz biorąc, za każdym razem, gdy używasz strcmp, strncmp jest prawdopodobnie bezpieczniejszą opcją.
jestem prawie pewien, że to tylko marnowanie procesora. wszystko, co musisz sprawdzić, dla StarstWith i EndsWith, to po prostu sprawdzenie, czy bajty się zgadzają, i właśnie to robi zaakceptowana odpowiedź. ta 1 marnuje czas na obliczanie liczby znaków utf8 igły, a gdzie n-ty znak utf8 stogu siana jest .. myślę, że bez 100% pewności, to tylko strata procesora. czy możesz wymyślić rzeczywisty przypadek testowy, w którym zaakceptowana odpowiedź kończy się niepowodzeniem, a to nie?
hanshenrik
2
@hanshenrik - może się to zdarzyć przy okazji, w bardzo rzadkim przypadku, gdy szukasz łańcucha zawierającego te same bajty co UTF8, ale brakuje połowy ostatniego znaku. Na przykład, masz Unicode C5 91 (litera „ő”) i szukasz C5 (litera „Å”), nie powinno ono pasować. Z drugiej strony, jasne, dlaczego miałbyś przeszukiwać stóg siana utf w poszukiwaniu igły innej niż utf ... Ale w przypadku kontroli kuloodpornych należy to rozważyć.
dkellner
W startsWithpowinno być$length = mb_strlen($needle, 'UTF-8');
Thomas Kekeisen
2
@ThomasKekeisen Dzięki, naprawiłem to.
Vahid Amiri,
8
Krótkie i łatwe do zrozumienia jedno-linijki bez wyrażeń regularnych.
StartWith () jest prosty.
function startsWith($haystack, $needle){return(strpos($haystack, $needle)===0);}
EndWith () używa nieco fantazyjnego i wolnego strrev ():
function endsWith($haystack, $needle){return(strpos(strrev($haystack), strrev($needle))===0);}
@FrancescoMM: strpos nie jest „właściwym narzędziem” ... Dlaczego? Jakie są zatem „odpowiednie narzędzia”? EDYCJA: Przeczytałem twoją odpowiedź poniżej. Myślałem, że programowanie jest jak wynalazek z wykorzystaniem posiadanych zasobów. Więc nie ma w tym nic dobrego ani złego ... tylko działa lub nie działa ... wydajność ma drugorzędne znaczenie.
Fr0zenFyr
„ponieważ jest to narzędzie do wyszukiwania, a nie do porównywania?” Cit. Aristoteles
FrancescoMM
7
Skupienie się na początkach, jeśli masz pewność, że łańcuchy nie są puste, dodanie testu dla pierwszego znaku, przed porównaniem, strlen itp., Nieco przyspiesza:
function startswith5b($haystack, $needle){return($haystack{0}==$needle{0})?strncmp($haystack, $needle, strlen($needle))===0:FALSE;}
Jest w jakiś sposób (20% -30%) szybszy. Dodanie kolejnego testu char, np. $ Haystack {1} === $ igła {1}, wydaje się nie przyspieszać, może nawet spowolnić.
===wydaje się szybszy niż ==
Operator warunkowy (a)?b:cwydaje się szybszy niżif(a) b; else c;
Dla tych, którzy pytają „dlaczego nie użyć strpos?” nazywając inne rozwiązania „niepotrzebną pracą”
strpos jest szybki, ale nie jest odpowiednim narzędziem do tego zadania.
With strccmp, etc...is a===b? NO
returnfalseWith strpos
is a===b? NO -- iterating in haysack
is a===c? NO
is a===d? NO
....is a===g? NO
is a===g? NO
is a===a? YES
is1===1? YES -- iterating in needle
is2===3? YES
is4===4? YES
....is8===8? YES
is c===x? NO: oh God,is a===1? NO -- iterating in haysack again
is a===2? NO
is a===3? NO
is a===4? NO
....is a===x? NO
is a===b? NO
is a===b? NO
is a===b? NO
is a===b? NO
is a===b? NO
is a===b? NO
is a===b? NO
...... may many times......is a===b? NO
is a===a? YES -- iterating in needle again
is1===1? YES
is2===3? YES
is4===4? YES
is8===8? YES
is c===c? YES YES YES I have found the same string! yay!
was it at position 0? NOPE
What you mean NO?So the string I found is useless?YEs.Damn.returnfalse
Zakładając, że strlen nie iteruje całego łańcucha (ale nawet w takim przypadku), nie jest to wcale wygodne.
Przyspieszenie następuje tylko wtedy, gdy pierwsze postacie są różne.
Ja͢ck
2
@Jack tak, oczywiście chodzi o to, że dzieje się to statystycznie, więc przyspieszenie wynosi ogólnie 20% -30% w całym zestawie testowym (włączając przypadki, w których nie jest inaczej). Zyskujesz dużo, gdy są różne, a tracą bardzo mało, gdy nie są. Średnio zyskujesz to 30% (różni się w zależności od zestawu, ale głównie zyskujesz prędkość w dużych testach)
FrancescoMM
„ale to nie jest odpowiednie narzędzie do tego zadania” … Jakieś cytaty?
Fr0zenFyr
1
WTF. Wymieniłem cały proces poniżej, kogo powinienem zacytować. Czy użyłbyś funkcji, która wyszukuje do końca łańcucha, aby powiedzieć, że pierwszy znak nie jest „a”? Czy to kogo to obchodzi? To nie jest właściwe narzędzie, ponieważ jest to narzędzie do wyszukiwania, a nie do porównywania, nie ma potrzeby cytowania Aristotelesa, aby stwierdzić oczywistość!
FrancescoMM
6
Mam nadzieję, że poniższa odpowiedź może być skuteczna, a także prosta:
$content ="The main string to search";
$search ="T";//For compare the begining string with case insensitive. if(stripos($content, $search)===0) echo 'Yes';else echo 'No';//For compare the begining string with case sensitive. if(strpos($content, $search)===0) echo 'Yes';else echo 'No';//For compare the ending string with case insensitive. if(stripos(strrev($content), strrev($search))===0) echo 'Yes';else echo 'No';//For compare the ending string with case sensitive. if(strpos(strrev($content), strrev($search))===0) echo 'Yes';else echo 'No';
Zazwyczaj ostatnio kończę na bibliotece takiej jak podkreślenie-php .
require_once("vendor/autoload.php");//use if neededuseUnderscore\Types\String;
$str ="there is a string";
echo(String::startsWith($str,'the'));// 1
echo(String::endsWith($str,'ring'));// 1
Odpowiedź przez MPpl jest niezwykle dokładny, ale, niestety, pod warunkiem odniesienia ma bardzo istotny i niekorzystny nadzoru.
Ponieważ każdy bajt w igłach i stogach siana jest całkowicie losowy, prawdopodobieństwo, że para igły i stogu siana będzie się różnić na pierwszym bajcie wynosi 99,609375%, co oznacza, że średnio około 99609 ze 100000 par będzie się różnić na pierwszym bajcie . Innymi słowy, test porównawczy jest mocno ukierunkowany na startswithimplementacje, które wyraźnie sprawdzają pierwszy bajt, jakstrncmp_startswith2 .
Jeśli zamiast tego implementowana jest pętla generująca testy, to:
wyniki testu porównawczego przedstawiają nieco inną historię:
strncmp_startswith:223.0 ms
substr_startswith:228.0 ms
substr_compare_startswith:238.0 ms
strncmp_startswith2:253.0 ms
strpos_startswith:349.0 ms
preg_match_startswith:20,828.7 ms
Oczywiście ten test porównawczy może nadal nie być całkowicie bezstronny, ale testuje wydajność algorytmów, gdy podaje się częściowo pasujące igły.
function startsWith($haystack,$needle){if($needle==="")returntrue;if($haystack[0]<>$needle[0])returnfalse;// ------------------------- speed boost!return(0===substr_compare($haystack,$needle,0,strlen($needle)));}
Ta dodatkowa linia, porównująca pierwszy znak ciągów, może sprawić, że fałszywy przypadek natychmiast powróci , dzięki czemu wiele twoich porównań będzie znacznie szybszych (7 razy szybszych, gdy mierzę). W prawdziwym przypadku za tę pojedynczą linię praktycznie nie płacisz żadnej ceny, więc myślę, że warto ją uwzględnić. (Ponadto w praktyce, gdy testujesz wiele ciągów dla określonej początkowej porcji, większość porównań zakończy się niepowodzeniem, ponieważ w typowym przypadku szukasz czegoś.)
function startWith($haystack,$needle){if(substr($haystack,0, strlen($needle))===$needle)returntrue;}function endWith($haystack,$needle){if(substr($haystack,-strlen($needle))===$needle)returntrue;}
Zapominanie o zwróceniu wartości false, jeśli nie pasuje. Błędny błąd, ponieważ wartość zwracana przez funkcję nie powinna być „zakładana”, ale wiem, o co chodzi, przynajmniej w porównaniu z innymi odpowiedziami.
Spoo
3
W oparciu o odpowiedź Jamesa Blacka, oto jego koniec W wersji:
Uwaga: zamieniłem część if-else dla funkcji Jamesa Blacka startWith, ponieważ strncasecmp jest w rzeczywistości rozróżniającą wielkość liter wersją strncmp.
Pamiętaj, że strrev()jest kreatywny, ale bardzo kosztowny, szczególnie jeśli masz ciągi powiedzmy ... 100 KB.
Alexis Wilke
Użyj ===zamiast, ==aby się upewnić. 0jest równy wielu rzeczom w PHP.
nawfal
3
Dlaczego nie następujące?
//How to check if a string begins with another string
$haystack ="valuehaystack";
$needle ="value";if(strpos($haystack, $needle)===0){
echo "Found ". $needle ." at the beginning of ". $haystack ."!";}
Wynik:
Znaleziono wartość na początku valuehaystack!
Pamiętaj, strposzwróci wartość false, jeśli igła nie została znaleziona w stogu siana, i zwróci 0, jeśli i tylko wtedy, gdy igła została znaleziona przy indeksie 0 (AKA początek).
A oto koniec:
$haystack ="valuehaystack";
$needle ="haystack";//If index of the needle plus the length of the needle is the same length as the entire haystack.if(strpos($haystack, $needle)+ strlen($needle)=== strlen($haystack)){
echo "Found ". $needle ." at the end of ". $haystack ."!";}
W tym scenariuszu nie ma potrzeby uruchamiania funkcji StartWith () as
Wydaje się dziwne, że jeśli szukasz „xy” wewnątrz ciągu „abcdefghijklmxyz” zamiast po prostu porównywać „x” z „a” i zwracać FAŁSZ, wyglądasz na każdą postać od „a” do „m”, a potem znajdujesz „xy” wewnątrz ciągu, a na końcu zwracasz FAŁSZ, ponieważ jego pozycja nie jest równa zero! To, co robisz, jest dziwne i dzikie niż jakakolwiek inna szalona funkcja tutaj.
FrancescoMM
Prostota polega na pisaniu, a nie na logice.
Kade Hafen
To nie tyle logika, ile możliwa optymalizacja, na którą wskazał Francsco. Używanie strpos()będzie wolne, chyba że będzie pasować. strncmp()w tym przypadku byłoby znacznie lepiej.
Alexis Wilke,
Kiedy wykonujesz takie funkcje na niskim poziomie, zwykle wybierasz rozwiązanie najbardziej zoptymalizowane pod kątem prędkości, bez względu na to, jak skomplikowane, ponieważ będzie to nazywane miliony razy. Każda mikrosekunda, którą tu zyskujesz lub tracisz, robi bardzo istotną różnicę. Więc lepiej podkręć piekło (a potem zapomnij o złożoności, teraz, gdy masz już tę funkcję), zamiast wybierać wygląd i stracić przerażającą ilość czasu później, gdy nawet nie wiesz, co poszło nie tak. Wyobraź sobie sprawdzanie ciągu 2 GB, który nie pasuje.
dkellner
3
Wiele wcześniejszych odpowiedzi będzie działać równie dobrze. Jest to jednak możliwie jak najkrótsze i możesz zrobić to, co chcesz. Po prostu oświadczasz, że chciałbyś, aby „zwrócił prawdę”. Dołączyłem więc rozwiązania zwracające wartość logiczną prawda / fałsz i tekstowe prawda / fałsz.
Prawdziwe. Jednak Peter prosił o funkcję, która działałaby z ciągami znaków. Niemniej jednak zaktualizowałem moją odpowiedź, aby cię uspokoić.
wynshaft
Po edycji rozwiązanie jest teraz całkowicie przestarzałe. Zwraca 'true'i 'false'jako ciągi znaków, które mają truelogiczne znaczenie. Jest to jednak dobry wzór na coś takiego jak underhanded.xcott.com ;)
Tino
Cóż, Peter właśnie stwierdził, że chce, aby zwrócił się „prawdziwy”. Pomyślałem więc, że zwrócę to, o co prosił. Dodałem obie wersje, na wypadek, gdyby nie tego chciał.
wynshaft
2
Możesz także użyć wyrażeń regularnych:
function endsWith($haystack, $needle, $case=true){return preg_match("/.*{$needle}$/".(($case)?"":"i"), $haystack);}
s($str)->startsWith('|')
is($str)->endsWith('}')
pomocny, jak w tej samodzielnej bibliotece .Odpowiedzi:
Użyj tego, jeśli nie chcesz używać wyrażenia regularnego.
źródło
$length
nie jest potrzebny w ostatnim wierszu plikuendsWith()
.return substr($haystack, -strlen($needle))===$needle;
if
całkowicie przekazując$length
jako trzeci parametrsubstr
:return (substr($haystack, -$length, $length);
. To rozwiązuje przypadek$length == 0
zwracając pusty ciąg, a nie całość$haystack
.Możesz użyć
substr_compare
funkcji, aby sprawdzić początek i koniec:To powinno być jedno z najszybszych rozwiązań na PHP 7 ( skrypt porównawczy ). Testowany na stogach siana o pojemności 8 KB, różnych długościach igieł oraz pełnych, częściowych i niepasujących skrzyniach.
strncmp
jest odrobinę szybszy na początku, ale nie może sprawdzić końca.źródło
strrpos
która (powinna) zawieść natychmiast, jeśli igła nie pasuje do początku stogu siana.-strlength($haystack)
) i szukamy stamtąd wstecz ? Czy to nie znaczy, że niczego nie przeszukujesz? Nie rozumiem też!== false
części tego. Zgaduję, że opiera się to na dziwactwie PHP, w którym niektóre wartości są „prawdziwe”, a inne „fałszywe”, ale jak to działa w tym przypadku?xxxyyy
igła =yyy
i korzystaniestrrpos
z wyszukiwania rozpoczyna się od pierwszegox
. Teraz nie mamy udany mecz tutaj (znaleziono x zamiast y) i nie możemy już iść do tyłu (jesteśmy na początku łańcucha) poszukiwanie nie natychmiast . O użyciu!== false
-strrpos
w powyższym przykładzie zwróci 0 lub false, a nie inną wartość. Podobniestrpos
w powyższym przykładzie może zostać zwrócona$temp
(oczekiwana pozycja) lub fałszywa. Poszedłem z!== false
konsekwencją, ale można było użyć odpowiednio=== 0
i=== $temp
funkcji.Zaktualizowano 23 sierpnia 2016 r
Funkcje
Testy
Wyniki (PHP 7.0.9)
(Posortowane od najszybszego do najwolniejszego)
Wyniki (PHP 5.3.29)
(Posortowane od najszybszego do najwolniejszego)
openswith_benchmark.php
źródło
function startswith5b($haystack, $needle) {return ($haystack{0}==$needle{0})?strncmp($haystack, $needle, strlen($needle)) === 0:FALSE;}
dodałem odpowiedź poniżej.Wszystkie odpowiedzi do tej pory wydaje się robić mnóstwo niepotrzebnej pracy
strlen calculations
,string allocations (substr)
itp'strpos'
i'stripos'
zwracają indeks pierwszego wystąpienia$needle
w$haystack
:źródło
endsWith()
funkcja ma błąd. Pierwszą linią powinien być (bez -1):$expectedPosition = strlen($haystack) - strlen($needle);
strpos($haystack, "$needle", 0)
czy istnieje jakikolwiek szansa nie jest już łańcuch (na przykład jeśli pochodzi zjson_decode()
). W przeciwnym razie [nieparzyste] domyślne zachowaniestrpos()
może spowodować nieoczekiwane wyniki: „ Jeśli igła nie jest łańcuchem, jest konwertowana na liczbę całkowitą i stosowana jako wartość porządkowa znaku. ”Kredyt dla :
Sprawdź, czy łańcuch kończy się innym łańcuchem
Sprawdź, czy ciąg zaczyna się od innego ciągu
źródło
Wyrażenia regularne działają powyżej, ale z innymi poprawkami również sugerowanymi powyżej:
źródło
To pytanie ma już wiele odpowiedzi, ale w niektórych przypadkach możesz zadowolić się czymś prostszym niż wszystkie. Jeśli ciąg, którego szukasz, jest znany (zakodowany na stałe), możesz używać wyrażeń regularnych bez cudzysłowu itp.
Sprawdź, czy ciąg zaczyna się od „ABC”:
kończy się na „ABC”:
W moim prostym przypadku chciałem sprawdzić, czy ciąg kończy się ukośnikiem:
Zaleta: ponieważ jest bardzo krótka i prosta, nie trzeba definiować funkcji (takich jak
endsWith()
), jak pokazano powyżej.Ale znowu - to nie jest rozwiązanie dla każdego przypadku, tylko ten bardzo konkretny.
źródło
@
, aby ukośnik (/
) nie musiał uciekać. Zobacz przykład 3 tutaj: php.net/manual/en/function.preg-match.php .Jeśli prędkość jest dla Ciebie ważna, spróbuj tego (uważam, że jest to najszybsza metoda)
Działa tylko dla ciągów znaków i jeśli $ stóg siana ma tylko 1 znak
źródło
endsWithChar('','x')
ale wynik jest poprawnyOto dwie funkcje, które nie wprowadzają tymczasowego ciągu, które mogą być przydatne, gdy igły są znacznie duże:
źródło
endsWidth
powinien zrobićreturn $needle==='' || substr_compare(
... więc działa zgodnie z oczekiwaniami-strlen($needle)===0
, a bez poprawkiendsWith('a','')
zwracafalse
substr_compare()
, więc dodałem PR, aby to naprawić :)endsWith('', 'foo')
wyzwala Ostrzeżenie: „substr_compare (): Pozycja początkowa nie może przekroczyć początkowej długości łańcucha”. Może to kolejny błądsubstr_compare()
, ale aby tego uniknąć, potrzebujesz wstępnej kontroli, takiej jak ...|| (strlen($needle) <= strlen($haystack) && substr_compare(
...) === 0);
return $needle === '' || @substr_compare(
..., aby ukryć to ostrzeżenie.Najszybsze rozwiązanie Rozwiązanie ():
Reper:
Wyniki testu:
źródło
Zdaję sobie sprawę, że zostało to zakończone, ale możesz chcieć spojrzeć na strncmp, ponieważ pozwala on ustawić długość łańcucha do porównania, więc:
źródło
Możesz użyć
strpos
istrrpos
źródło
strpos($sHaystack, $sNeedle) == 0
takstrpos($sHaystack, $sNeedle) === 0
? Widzę błąd, gdyfalse == 0
oceniatrue
.Oto wielobajtowa bezpieczna wersja zaakceptowanej odpowiedzi, działa dobrze dla ciągów UTF-8:
źródło
startsWith
powinno być$length = mb_strlen($needle, 'UTF-8');
Krótkie i łatwe do zrozumienia jedno-linijki bez wyrażeń regularnych.
StartWith () jest prosty.
EndWith () używa nieco fantazyjnego i wolnego strrev ():
źródło
Skupienie się na początkach, jeśli masz pewność, że łańcuchy nie są puste, dodanie testu dla pierwszego znaku, przed porównaniem, strlen itp., Nieco przyspiesza:
Jest w jakiś sposób (20% -30%) szybszy. Dodanie kolejnego testu char, np. $ Haystack {1} === $ igła {1}, wydaje się nie przyspieszać, może nawet spowolnić.
===
wydaje się szybszy niż==
Operator warunkowy(a)?b:c
wydaje się szybszy niżif(a) b; else c;
Dla tych, którzy pytają „dlaczego nie użyć strpos?” nazywając inne rozwiązania „niepotrzebną pracą”
strpos jest szybki, ale nie jest odpowiednim narzędziem do tego zadania.
Aby zrozumieć, oto mała symulacja jako przykład:
Co komputer robi „w środku”?
Zakładając, że strlen nie iteruje całego łańcucha (ale nawet w takim przypadku), nie jest to wcale wygodne.
źródło
Mam nadzieję, że poniższa odpowiedź może być skuteczna, a także prosta:
źródło
Zazwyczaj ostatnio kończę na bibliotece takiej jak podkreślenie-php .
Biblioteka jest pełna innych przydatnych funkcji.
źródło
Odpowiedź przez MPpl jest niezwykle dokładny, ale, niestety, pod warunkiem odniesienia ma bardzo istotny i niekorzystny nadzoru.
Ponieważ każdy bajt w igłach i stogach siana jest całkowicie losowy, prawdopodobieństwo, że para igły i stogu siana będzie się różnić na pierwszym bajcie wynosi 99,609375%, co oznacza, że średnio około 99609 ze 100000 par będzie się różnić na pierwszym bajcie . Innymi słowy, test porównawczy jest mocno ukierunkowany na
startswith
implementacje, które wyraźnie sprawdzają pierwszy bajt, jakstrncmp_startswith2
.Jeśli zamiast tego implementowana jest pętla generująca testy, to:
wyniki testu porównawczego przedstawiają nieco inną historię:
Oczywiście ten test porównawczy może nadal nie być całkowicie bezstronny, ale testuje wydajność algorytmów, gdy podaje się częściowo pasujące igły.
źródło
w skrócie:
źródło
Tylko zalecenie:
Ta dodatkowa linia, porównująca pierwszy znak ciągów, może sprawić, że fałszywy przypadek natychmiast powróci , dzięki czemu wiele twoich porównań będzie znacznie szybszych (7 razy szybszych, gdy mierzę). W prawdziwym przypadku za tę pojedynczą linię praktycznie nie płacisz żadnej ceny, więc myślę, że warto ją uwzględnić. (Ponadto w praktyce, gdy testujesz wiele ciągów dla określonej początkowej porcji, większość porównań zakończy się niepowodzeniem, ponieważ w typowym przypadku szukasz czegoś.)
źródło
startsWith("123", "0")
dajetrue
substr
Funkcja może powrócićfalse
w wielu przypadkach szczególnych, więc tutaj jest moja wersja, która zajmuje się tymi zagadnieniami:Testy (
true
znaczy dobre):substr_compare
Warto również sprawdzić tę funkcję. http://www.php.net/manual/en/function.substr-compare.phpźródło
To może działać
Źródło: https://stackoverflow.com/a/4419658
źródło
Zrobiłbym to w ten sposób
źródło
W oparciu o odpowiedź Jamesa Blacka, oto jego koniec W wersji:
Uwaga: zamieniłem część if-else dla funkcji Jamesa Blacka startWith, ponieważ strncasecmp jest w rzeczywistości rozróżniającą wielkość liter wersją strncmp.
źródło
strrev()
jest kreatywny, ale bardzo kosztowny, szczególnie jeśli masz ciągi powiedzmy ... 100 KB.===
zamiast,==
aby się upewnić.0
jest równy wielu rzeczom w PHP.Dlaczego nie następujące?
Wynik:
Pamiętaj,
strpos
zwróci wartość false, jeśli igła nie została znaleziona w stogu siana, i zwróci 0, jeśli i tylko wtedy, gdy igła została znaleziona przy indeksie 0 (AKA początek).A oto koniec:
W tym scenariuszu nie ma potrzeby uruchamiania funkcji StartWith () as
zwróci dokładnie prawda lub fałsz.
Wydaje się dziwne, że jest to takie proste, gdy szaleją tu wszystkie dzikie funkcje.
źródło
strpos()
będzie wolne, chyba że będzie pasować.strncmp()
w tym przypadku byłoby znacznie lepiej.Wiele wcześniejszych odpowiedzi będzie działać równie dobrze. Jest to jednak możliwie jak najkrótsze i możesz zrobić to, co chcesz. Po prostu oświadczasz, że chciałbyś, aby „zwrócił prawdę”. Dołączyłem więc rozwiązania zwracające wartość logiczną prawda / fałsz i tekstowe prawda / fałsz.
źródło
'true'
i'false'
jako ciągi znaków, które majątrue
logiczne znaczenie. Jest to jednak dobry wzór na coś takiego jak underhanded.xcott.com ;)Możesz także użyć wyrażeń regularnych:
źródło
preg_quote($needle, '/')
.Pętla bez kopii i bez internowania:
źródło
Oto wydajne rozwiązanie dla PHP 4. Możesz uzyskać szybsze wyniki, jeśli na PHP 5, używając
substr_compare
zamiaststrcasecmp(substr(...))
.źródło
Możesz użyć do tego funkcji fnmatch .
źródło