Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: preg_match()
Forum PHP.pl > Forum > PHP
cudny
Witam, mam problem z wyrażeniem regularnym, poniżej przykład jak chciałem to rozwiązać, niestety nie działa.

  1.  
  2. $string = '1,2,3,4,5,6,7';
  3.  
  4. echo preg_match('/(1|3|5){2}/', $string);
  5.  


Chodzi o to, aby sprawdzić czy w $string istnieje jedynka i trójka i piątka.
Oczywiście cyfry są tylko dla ułatwienia, w rzeczywistości są to ciągi znaków i kolejność nigdy nie jest taka sama.
Moje wyrażenie miało sprawdzić czy w stringu istnieje 1 lub 3 lub 5 dokładnie trzy razy, co wydaje się być logiczne i powinno działać, niestety z tego co widzę parser zwraca wystąpienie tylko raz przy pierwszym napotkanym true.

Bardzo proszę o pomoc. Jak znaleźć czy w stringu istnieje 1 i 3 i 5.
Dokładnie tłumacząc to co mam na myśli: $string może składać się z czegokolwiek ale musi zawierać 1 i 3 i 5 gdzie kolejność cyfr w $string jest przypadkowa.
Sephirus
A może by tak użyć substr_count()

Ta funkcja zwraca liczbę wystąpień podanego ciągu w ciągu - a więc coś chyba o co Ci chodzi.

Możesz napisac na jej podstawię taką funkcję, która sprawdzi podane wszystkie możliwe cyfry czy występują w podanym ciągu znaków tyle razy ile mają wink.gif

Prosty przykład:
  1. function waliduj_string($string, $tablicaCyfr, $minimumWystapien)
  2. {
  3. foreach($tablicaCyfr AS $c) if(substr_count($string,$c) < $minimumWystapien) return false;
  4. return true;
  5. }
cudny
smile.gif nie chodzi mi o funkcję, to musi być wyrażenie regularne, będzie ono wykorzystywane zarówno w MySQL jak i PHP
Sephirus
Jedyne co mi zatem przychodzi do głowy to "bezczelne" sprawdzanie ale jest zupełnie nie konfigurowalne :/

  1. preg_match('/(.*1+.*3+.*5+.*)|(.*1+.*5+.*3+.*)|(.*3+.*1+.*5+.*)|(.*3+.*5+.*1+.*)|(.*5+.*1+.*3+.*)|(.*5+.*3+.*1+.*)/si',$string);


W.R. niestety zwracają uwagę na kolejność - wydaje mi się że tylko w ten sposób możesz być pewien że na bank w tym ciągu występuję 1,3,5 w dowolnej kolejności ;/

Jeżeli się mylę chętnie dowiem się jak można to zrobić inaczej ;P
cojack
"/(1)\d+(3)\d+(5)\d+/"

@edit

z tym że string to "123465789"
cudny
  1. echo preg_match('/(^|,)(1|3|5).*(1|3|5).*(1|3|5)(,|$)/','1,2,3,4,5,6');


tak jest prościej, ale muszę powiedzieć, że mnie to nie satysfakcjonuje, tym bardziej, że szukanych może być na prawdę dużo ;(
Jak ktoś ma jakiś dobry pomysł to proszę o sugestie, ehh

Cytat(cojack @ 4.11.2011, 15:27:00 ) *
"/(1)\d+(3)\d+(5)\d+/"

@edit

z tym że string to "123465789"


Pisałem, że kolejność może być inna, czyli jeśli $string przyjmie wartość 987654321 to już nie wyłapie
Sephirus
Nie jest prościej bo jest źle smile.gif String "111" albo "553" przejdzie przez tego preg_matcha ;P

Mi się wydaję, że się nie da smile.gif właśnie przez tą kolejność ;/ Ale życzę powodzenia ;P
blooregard
Coś takiego wymodziłem:

  1. '/.*([1|3|5]).*([1|3|5]).*([1|3|5]).*/'


ale musisz sprawdzić na swoich stringach, czy działa prawidłowo
cudny
Cytat(Sephirus @ 4.11.2011, 15:35:35 ) *
Nie jest prościej bo jest źle smile.gif String "111" albo "553" przejdzie przez tego preg_matcha ;P

Mi się wydaję, że się nie da smile.gif właśnie przez tą kolejność ;/ Ale życzę powodzenia ;P

No nie dodałem, że w $string każda fraza może wystapić tylko i wyłącznie raz.
Może być 1,2,3,4 ale nie może być 1,1,2,3

Cytat(blooregard @ 4.11.2011, 15:39:52 ) *
Coś takiego wymodziłem:

  1. '/.*([1|3|5]).*([1|3|5]).*([1|3|5]).*/'


ale musisz sprawdzić na swoich stringach, czy działa prawidłowo


dziala, ale tak jak napisal sephirus, przejdzie kazda fraza

Ogólnie chodziło mi o to żeby zapis był krótki i czytelny, tak jak, np. ((1)|(2)|(3)){3} (szkoda, że nie działa).
No nic, w takim wypadku będę musiał osobno pisać pod SQL procedurę powtarzającą FIND_IN_SET(); a w PHP to już bzdurka tongue.gif równie dobrze mogę wykorzystać explode i dać in_array();
Jak ktoś znajdzie jakieś sensowne rozwiązanie, zakładając, że szukanych jest dziesiątki, a nie tylko trzy sztuki to bardzo proszę o napisanie tego w tym poście
blooregard
Cytat
dziala, ale tak jak napisal sephirus, przejdzie kazda fraza


Kurczę, faktycznie.

Hmm, ciekawy problem tongue.gif
Sephirus
Ok skoro jeszcze chcesz bez powtórzeń to wymiękam tongue.gif Wydaje mi się, że preg_match też ;P

Swoją drogą dodam tylko, że mój sposób bez preg_matchy może być bez problemu wykonany również przez funkcję z SQL gdybyś chciał to ładnie zrobić to i PHP i SQL to łykną bez wyrażeń wink.gif
melkorm
Może po prostu napisz o jaki konkretny problem chodzi? Bo mam wrażenie że szukasz rozwiązania bardzo na około.

Bo raz piszesz:
Cytat
Moje wyrażenie miało sprawdzić czy w stringu istnieje 1 lub 3 lub 5 dokładnie trzy razy,


a zaraz:
Cytat
No nie dodałem, że w $string każda fraza może wystapić tylko i wyłącznie raz.
cudny
Ale baaaardzo duże ciągi by to były smile.gif
Napisanie wyrażenia nie stanowi dla mnie większej trudności tongue.gif Problemem jest zrobienie tego zgrabnie i przede wszystkim wydajnie.
Zrobię sobie procedurkę w SQL, a dla PHP napiszę jakąś funkcję smile.gif
Oczywiście nadal czekam na pomysły smile.gif

Jak sprawdzić czy zbiór: 1,2,3,4,5 zawiera 1 i 3 i 5 smile.gif


melkorm cyt. "Może po prostu napisz o jaki konkretny problem chodzi? Bo mam wrażenie że szukasz rozwiązania bardzo na około."

A ja się spytam: Co ma piernik do wiatraka ?
Przeczytaj o co chodzi w poście, a potem odpowiedz sensownie, bo jak nie znasz odpowiedzi to spamuj gdzie indziej
melkorm
Do spamerów raczej nie należę, ale najwidoczniej sam nie potrafisz sobie sam odpowiedzieć na to co chcesz, przychodzisz pytasz o pomoc, jakbyś nakreślił dokładnie problem i warunki o wiele łatwiej byłoby nam zdiagnozować problem i/lub znaleźć bardziej optymalne / czytelniejsze / łatwiejsze rozwiązanie.

PS. Jeżeli sądzisz że pomaganie na forum to tylko ślepe udzielanie odpowiedzi na zadane pytania bez podsuwania ewentualnych, prostszych i łatwiejszych rozwiązań to się grubo mylisz.
PS2. Jeżeli masz zamiar znowu pisać o jakiejkolwiek formie mojego spamowania to sobie daruj, bo raczej nie znasz pojęcia `spamowanie`.
PS3. Wątek przeczytałem cały.
cudny
Cytat(melkorm @ 4.11.2011, 16:02:36 ) *
Może po prostu napisz o jaki konkretny problem chodzi? Bo mam wrażenie że szukasz rozwiązania bardzo na około.

Bo raz piszesz:


a zaraz:



Cytat(melkorm @ 4.11.2011, 16:16:35 ) *
Do spamerów raczej nie należę, ale najwidoczniej sam nie potrafisz sobie sam odpowiedzieć na to co chcesz, przychodzisz pytasz o pomoc, jakbyś nakreślił dokładnie problem i warunki o wiele łatwiej byłoby nam zdiagnozować problem i/lub znaleźć bardziej optymalne / czytelniejsze / łatwiejsze rozwiązanie.

PS. Jeżeli sądzisz że pomaganie na forum to tylko ślepe udzielanie odpowiedzi na zadane pytania bez podsuwania ewentualnych, prostszych i łatwiejszych rozwiązań to się grubo mylisz.
PS2. Jeżeli masz zamiar znowu pisać o jakiejkolwiek formie mojego spamowania to sobie daruj, bo raczej nie znasz pojęcia `spamowanie`.
PS3. Wątek przeczytałem cały.


Inni zrozumieli tongue.gif
Nie bierz tego do siebie hehe chodzi o to, że jedno z drugim się nie wykluczało.

Zobacz:
Cytat
Moje wyrażenie miało sprawdzić czy w stringu istnieje 1 lub 3 lub 5 dokładnie trzy razy,

I podałem przykład: $string = '1,2,3,4,5,6';
1 lub 3 lub 5 mają wystąpić dokładnie trzy razy - i tutaj to nie porozumienie - trzy razy czyli raz jedynka, raz trójka i raz piątka - daje 3 ? smile.gif
Cytat
No nie dodałem, że w $string każda fraza może wystapić tylko i wyłącznie raz.

A tutaj wyraźnie napisałem, że w $string czyli 1,2,3,4,5,6 posiada tylko i wyłącznie po jednej sztuce 1 i 2 i 3 i 4 i 5 i 6
Dla tego logiczne wydało mi się, że preg_match('/((1)|(3)|(5)){3}/', '1,2,3,4,5,6'); zwróci true tylko i wyłącznie przy wystąpieniu którejkolwiek z fraz po jednym razie, a tu kupa tongue.gif po pierwszym wystąpieniu zwraca true i przerywa - czyli ((1)|(3)|(5)) nigdy nie wystąpi trzy razy.

Doszedłem do wniosku, że chyba nie da się wyrażeniami tego rozwiązać (oczywiście nie dłuuuugaśnymi, już lepiej zrobić ładną funkcję, która będzie pewnie bardziej wydajna).
Oczywiście jeżeli ktoś wykaże, że się mylę będę niezmiernie wdzięczny smile.gif

melkorm - sorki, oceniłem twojego posta jako atak tongue.gif




Rozwiązanie:

Dla tego co jest podane wyżej rozwiązanie raczej istnieje tylko i wyłącznie poprzez robienie dluuugich wyrażeń używających olbrzymiej ilości logicznego OR, co jak pisałem mija się z celem i jest nie wydajne.
Mam jednak możliwość posortowania tego (nie napisałem tego wcześniej bo nie wiedziałem), więc da się to zrobić najprościej na świecie:

  1. $string = '1,3,5,7,8,10';
  2. // szukamy czy jest 3 i 7 i 10
  3. echo preg_match('/(,|^)3,[,0-9]+,7,[,0-9]+,10(,|$)/', $string); // zwróci true
  4. // szukamy czy jest 2,7,10
  5. echo preg_match('/(,|^)2,[,0-9]+,7,[,0-9]+,10(,|$)/', $string); // zwróci false


Chodzi o to że jeżeli wiem, że cyfry w $string są rosnące i cyfry, których szukam też to zawsze po 3 będzie 7 a po niej będzie 10 i tak dalej

Proszę nie zamykać tematu, może jednak ktoś ma jakieś fajne rozwiązanie nie używając sortowania, było by to ciekawe smile.gif
melkorm
Cytat
Inni zrozumieli

Ja też, ale po Twoich wyjaśnieniach wyszło że i tak źle zrozumiałem bo wybrałem zły tok myślenia smile.gif

Cytat
Doszedłem do wniosku, że chyba nie da się wyrażeniami tego rozwiązać (oczywiście nie dłuuuugaśnymi, już lepiej zrobić ładną funkcję, która będzie pewnie bardziej wydajna).

I dobrze myślisz, jeżeli się da to lepiej unikać wyrażeń regularnych (upraszczając oczywiście).

Cytat
melkorm - sorki, oceniłem twojego posta jako atak

Spoko, zapomniałem wstawić kilku fikuśnych emotek i jakoś powiało grozą z tego posta biggrin.gif

PS. Jak zrobisz, to wstaw swoje rozwiązania, z chęcią zobaczę jak to w końcu wyszło.
pyro
Cytat(cudny)
Doszedłem do wniosku, że chyba nie da się wyrażeniami tego rozwiązać (oczywiście nie dłuuuugaśnymi, już lepiej zrobić ładną funkcję, która będzie pewnie bardziej wydajna).


No cóż... mylić się jest rzeczą ludzką

Cytat(melkorm)
I dobrze myślisz, jeżeli się da to lepiej unikać wyrażeń regularnych (upraszczając oczywiście).


To znaczy, że musisz jeść więcej warzyw.

  1. preg_match('|1[^1]+?3[^13]+?5[^135]*$|', $string);


Możliwe, że czegoś nie zrozumiałem, ale to wyrażenie powinno sprawdzić czy w $string występują dane liczby tylko raz w danej kolejności. Chyba o to chodziło?
melkorm
Cytat
Oczywiście cyfry są tylko dla ułatwienia, w rzeczywistości są to ciągi znaków i kolejność nigdy nie jest taka sama.


Raczej na Twoje rozwiązanie ktoś by wcześniej wpadł gdyby kolejność była ustalona.
pyro
Cytat(melkorm @ 4.11.2011, 17:12:30 ) *
Raczej na Twoje rozwiązanie ktoś by wcześniej wpadł gdyby kolejność była ustalona.


Rozumiem, ale to również nie problem smile.gif

Proszę:

  1. preg_match('|([135])[^\1]*?([135])[^\1\2]*?([135])[^\1\2\3]*$|', $string);
cudny
Cytat(pyro @ 4.11.2011, 17:32:23 ) *
Rozumiem, ale to również nie problem smile.gif

Proszę:

  1. preg_match('|([135])[^\1]*?([135])[^\1\2]*?([135])[^\1\2\3]*$|', $string);



  1. $string = '11,55,33';

Dla takich wartości też zwróci true. Chociaż pomysł nie głupi smile.gif

Ok smile.gif udało mi się hehe.
Oczywiście wiem, że tylko ja wiem do czego to ma służyć i jak powinno wyglądać dokładnie, więc było mi duuuużo łatwiej niż Wam, ale i tak ciesze się, że mi się udało tongue.gif

to czego szukam to nie są liczby jak już pisałem. są to ID które ukrywają w sobie także inne dane wykorzystywane później, ale mniejsza z tym.
Ciąg, w którym szukam wygląda mniej więcej tak:
  1. $string = '1_1_1,1_1_2,1_2_1,1_2_2,1_3_1,1_4_1';

W $string nie ma możliwości aby się powtarzały poszczególne ID, to znaczy nie może to być:
  1. $string = '1_1_1,1_1_1,1_2_1,1_2_2,1_3_1,1_4_1';

bo 1_1_1 powtarza się. Jest to zabezpieczone dużo wcześniej i nie będzie takiej sytuacji.
W $string muszą być takie oto ID: 1_1_2 i 1_1_1 i 1_4_1
Powyższe ID muszą być wszystkie dokładnie po jednym razie każdy.
Rozwiązanie:
  1. $string = '1_1_1,1_1_2,1_2_1,1_2_2,1_3_1,1_4_1';
  2. $search = '1_1_2,1_2_2,1_1_1';
  3. echo preg_match('/^((1_1_1)|(1_1_2)|(1_2_1)|(1_2_2)|(1_3_1)|(1_4_1)|,){5}$/', '1_1_2,1_2_2,1_1_1'); // zwróci true
  4. $search = '1_1_2,1_2_2,1_1_4';
  5. echo preg_match('/^((1_1_1)|(1_1_2)|(1_2_1)|(1_2_2)|(1_3_1)|(1_4_1)|,){5}$/', '1_1_2,1_2_2,1_1_4'); // zwróci false


Po prostu odwróciłem troszki to czego szukam.
Chodzi o to, że $search może składać się tylko i wyłącznie z tego co jest w $string i to musi się powtórzyć tyle razy ile jest szukanych w $search + ilość przecinków czyli 1_1_2 + 1_2_2 + 1_1_4 + dwa przecinki = {5}

Jak się podoba smile.gif ?
To jest wersja lo-fi głównej zawartości. Aby zobaczyć pełną wersję z większą zawartością, obrazkami i formatowaniem proszę kliknij tutaj.
Invision Power Board © 2001-2025 Invision Power Services, Inc.