Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: [PHP]preg_match_all
Forum PHP.pl > Forum > Przedszkole
Crenos
Nie wiem kompletnie jak napisać wzorzec do tej funkcji. Przeczytałem kilka razy Wiki: http://en.wikipedia.org/wiki/Regular_expression bawiłem się tym narzędziem http://rubular.com/
Ale nic sensownego mi nie wychodzi.

mam taki string

Cytat
pierwszy string { drugi string|trzeci string {czwarty string|piąty string}}|szósty string {{ósmy string|dziewiąty string} dziesiąty string}{jedenasty string|dwunasty string} trzynasty string


chciałbym aby wyglądał tak

  1. (
  2. [0] => Array
  3. (
  4. [0] => pierwszy string
  5. [1] => { drugi string|trzeci string {czwarty string|piąty string}}
  6. )
  7.  
  8. [1] => Array
  9. (
  10. [0] => szósty string
  11. [1] => {{ósmy string|dziewiąty string} dziesiąty string}
  12. [2] => {jedenasty string|dwunasty string}
  13. [3] => trzynasty string
  14. )
  15.  
  16. )


To oczywiście nie jest wszystko co bym chciał zrobić z tym stringme ale jeżeli ogarnę to myślę, że dalej sobie porodzę. Tylko poprosiłbym o prosty opis dokładnie który fragment za co odpowiada.
A odnośnie wzorca to chciałbym aby tak jak w przypadku array[0] separował string, który nie zawiera się w znakach {}, separował stringi w znakach {} ale żeby ilość { była równa ilości } oraz jeżeli pojawia się | żeby tworzył kolejna tablice po tym znaku.
Mam nadzieję, że w miarę przejrzyściej opisałem.
Pytanie jest też takie czy w ogóle da się to zrobić za jednym razem.
!*!
Pokaż co już masz.
Crenos
Z takim czymś walczyłem ale to nie działa tak jak bym chciał po zatym nie dokońca potrafię sobie poradzić z tym, żeby to podzielić tym znakiem |
Cytat
/([[:alpha:]]+\s[[:alpha:]]+)|([{^]+[^}]*.[^}]*.)/
artuross
Najlepiej chyba zaczac wyszukiwac zewnetrzne wartosci i dopiero pozniej zaweżac wyszukiwane jadac liniowo.

Czyli na koncu ma to wygladac tak?
Kod
Array
(
    [0] => Array
        (
            [0] => pierwszy string
            [1] => Array
                (
                    [0] => drugi string
                    [1] => cpzeci string
                )

        )

    [1] => Array
        (
            [0] => szosty string
            [1] => Array
                (
                    [0] => Array
                        (
                            [0] => osmy string
                            [1] => dziewiaty string
                        )

                    [1] => dziesiaty string
                )

            [2] => Array
                (
                    [0] => jedenasty string
                    [1] => dwunasty string
                )

            [3] => Array
                (
                    [1] => trzynasty string
                )

        )

)
Crenos
Dokładnie tak ma to wyglądać
I sam już nie wiem czy to ma być na wyrażeniach regularnych czy pętlami obrabiać ten string. Znalazłem nawet generator regexpów ale nie robi dokładnie tego co bym chciał i jeszcze nie potrafię zmodyfikować tego co mi wypluje.
artuross
Jednym preg_match tego nie zrobisz. Napisz prosty parser, natrafia na { to "otwiera" nowa tablice, natrafia na } to ja "zamyka" i przechodzi do kolejnego elementu, natrafia na | to przechodzi do kolejnego elementu aktualnie "aktywnej" tablicy.
Crenos
A znasz jakiś fajny tutorial od podstaw z przykładami? bo to co tutaj jest preg_match to dla mnie zbyt duży poziom abstrakcji. Bo niby jakiś wzorzec jestem w stanie ułożyć prawie działa ale, przyznaje się robię to na "pałę" i nie do końca rozumiem dla czego on tak działa chociaż wg. mnie działać powinien inaczej.
artuross
Chyba najlepiej samemu probowac: http://www.php.net/manual/en/book.pcre.php
Crenos
Stworzyłem takie coś dla takiego stringa
Kod
pierwszy string { drugi string|trzeci string {czwarty string|piąty string}} szósty string {{ósmy string| dziewiąty string} dziesiąty string}{jedenasty string| dwunasty string} trzynasty string

To bez problemu pobiera substring do pierwszego {
Kod
(^[^{]+)

Ten wzorzec pobiera "{ drugi string|trzeci string {czwarty string|piąty string}}"
Kod
({[^{]+.+.}}+)

Czy ta się go jakoś dopasować aby pobierał x nawiasów czy muszę dla każdej opcji pisać oddzielny.

Problem mem jeszcze z pobraniem tego "szósty string"
Kod
([^}}]+.[{][{])

Tylko to zabiera ze sobą jeszcze na końcu {{
No i ostatni ciąg "trzynasty string" nie mam bladego pojęcia jak się zabrać do tego bo dubluje mi się z innymi wzorcami.
artuross
Uzywanie regexpa do tego jest kiepskim pomyslem. Lepiej sprawdzac po kolei kazdy znak, a poniewaz masz tylko 3 mozliwosci to jest to proste.

Uzyj case i sprawdzaj czy znak to {, } czy |, jako default po prostu dodaj znak do poprzednio aktywnej zmiennej (tablicy). Jezeli znak jest { to aktualna zmienna jest zamieniana na tablice i przechodzisz do 1. elementu (przekazanie przez referencje), jesli znak to | to po prostu nowy element w aktualnie aktywnej tablicy, jesli } to wychodzisz z tablicy (tutaj jest problem, bo musisz przejsc do tablicy wyzej, wiec musisz znalezc jakis prosty sposob).

Takie rozwiazanie zapewnia duza elastycznosc, mozesz takich stringow miec milion i nadal bedzie dzialalo.
Crenos
Cytat(artuross @ 2.04.2013, 23:12:11 ) *
jako default po prostu dodaj znak do poprzednio aktywnej zmiennej (tablicy)

A możesz pokierować mnie np jakimś przykładem ?
Bo to o czym piszesz już przerabiałem tylko zatrzymałem się w martwym punkcie ale nie robiłem tego na case tylko po prostu na pętli i na ifach
artuross
  1. $string = str_split('pierwszy string { drugi string|trzeci string {czwarty string|piąty string}} szósty string {{ósmy string| dziewiąty string} dziesiąty string}{jedenasty string| dwunasty string} trzynasty string', 1);
  2. $a = array();
  3.  
  4. foreach ( $string as $val )
  5. {
  6. switch ( $val )
  7. {
  8. case '{':
  9. // kod
  10. break;
  11. case '|':
  12. // kod
  13. break;
  14. case '}':
  15. // kod
  16. break;
  17. default:
  18. // kod
  19. break;
  20. }
  21. }


A jak tak sobie patrze, referencje do tablic (lub tez warstw, jak kto woli) wyzej wzgledem aktualnej mozna przechowywac w innej tablicy, gdzie ostatni element przechowuje np. $a[0][0][0], a n-1 $a[0][0].
Crenos
Chodziło mi o przejście do poprzednio aktywnej zmiennej(tablicy) smile.gif
artuross
Heh tego nie wiem, nie znam funkcji, ktora by to umozliwila, ale moze cos takiego:

  1. $c[0] =& $array;
  2. $c[1] =& $array[0];
  3. $c[2] =& $array[0][3];
  4. // itd.
  5.  
  6. case '}':
  7. $current =& $c[ count($c)-2 ];
  8.  
  9. // itd.
Crenos
Dobrze napisałem coś inaczej troszkę niż proponowałeś. Tzn to tak jak by pierwszy poziom obrabiania całości ale mam pewien problem z parametryzacją i przekazywaniem odpowiednich wartości.
Spłodziłem takie coś.

te zmienne na początku nie są istotne dodawałem je w momencie kiedy kombinowałem, żeby mi błędów o braku zdefiniowanej wartości zmiennej nie wywalało.

  1. $tekst = 'pierwszy string { drugi string|trzeci string {czwarty string|piąty string}} |szósty string {{ósmy string| dziewiąty string} dziesiąty string} {jedenasty string| dwunasty string} trzynasty string';
  2. $separator ='|';
  3. $znak = array('{', '}');
  4. $mam=0;
  5. $pZnak=array();
  6. $pStart=0;
  7. $tablica= array();
  8. $aTablica =0;
  9. $b=0;
  10. $a=0;
  11. $fragment = $tekst;
  12. function licz($fragment, $znak)
  13. { $b=0;
  14. $c=0;
  15. for ($a=0; $a < strlen( $fragment ); $a++)
  16. {
  17. if ( $fragment[$a] == $znak[0] )
  18. {
  19. $pZnak['{'][$b]=$a;
  20. $b++;
  21. }
  22. if ( $fragment[$a] == $znak[1] )
  23. {
  24. $pZnak['}'][$c]=$a;
  25. $c++;
  26. }
  27. }
  28. return $pZnak;
  29. }
  30. $zmienna = licz($fragment, $znak);
  31. print_r($zmienna);
  32. $pStart=0; //pozycja startowa do wyszykiwania
  33. while($i < strlen( $tekst )){
  34. if ($tekst[$i] != $znak[0]){ //sprawdzam czy $tekst[$i] jest różny {
  35. $pSeparator = stripos($tekst, $znak[0], $off); // sprawdzam pozycję najbliższego znaku {
  36. $fragment = substr($tekst, $pStart, $pSeparator); // pobieram fragment stringa do znaku {
  37. $tablica[$aTablica]= trim($fragment); // dodaje do tablicy fragment stringa
  38. $aTablica++;
  39. $i=$pSeparator; // przestawiam $i na pozcyję gdzie skończyłem przeszukiwania dla pętli
  40. $off = $pSeparator; // offset przestawiam na pozycje gdzie skończyłem przeszukiwanie dla funkcji stripos
  41. $pStart=$pSeparator; // pozycja startowa do przeszukiwania stringu
  42. //break;
  43. }
  44. elseif($tekst[$i] == $znak[0]){ //sprawdzam czy $tekst[$i] to znak {
  45. $fragment = substr($tekst, $pStart, strlen( $tekst )); //pobieram string od ostatniego sprawdzenia $pStart do końca
  46. $pzZnak = licz($fragment, $znak); // sprawdzaj pozycję wszystkich znaków { }
  47. while($d < count($pzZnak['{'])){ //dopsowuje zamkniecie do otwartych nawiasów
  48. if ( $pzZnak['{'][$d]>$pzZnak['}'][$d-1]){ // jeżeli pozycja znaku { jest większa od poprzedniej pozycji znaku } oznacza, że nawiazy pasują do siebie
  49. $pZamkniecie=$pzZnak['}'][$d-1]; // pobieram pozycję znaku } pasującego do {
  50. $d=count($pzZnak['{']); // wyłączam pętle
  51. }
  52. $d++;
  53. }
  54. $fragment = substr($fragment, 1, $pZamkniecie-1); //pobieram fragment tekstu gdzie ilość znaków { równa się ilości znaków } i wywalam brzegowe {}
  55. $tablica[$aTablica]= trim($fragment); // dodaje do tablicy
  56. $aTablica++;
  57. $i=$i+$pZamkniecie+1; // przestawiam $i na pozcyję gdzie skończyłem przeszukiwania dla pętli
  58. $off = $i+$pZamkniecie; // offset przestawiam na pozycje gdzie skończyłem przeszukiwanie dla funkcji stripos
  59. $pStart = $pStart+$pZamkniecie+1; // pozycja startowa do przeszukiwania stringu
  60. //break;
  61. }
  62. }


I powiedzmy działa to "prawie dobrze" bo: efekt jest taki:
Kod
Array
(
    [0] => pierwszy string
    [1] => drugi string|trzeci string {czwarty string|piąty string}
    [2] => |szósty string {{ósmy string| dziewiąty string} dziesiąty string} {jedenasty string| dwunasty string} trzynasty string
    [3] => jedenasty string| dwunasty string} trzynasty string
)


Problem polega na tym, że już w 3 rekordzie skrypt się gubi czyli $pStart i $off źle przekazują parametry. kombinowałem już na różne sposoby ale wydaje mi się że błąd leży w konstrukcji całości. Później będę to przebudowywał, żeby rozkładał cały ciąg do końca a nie tylko pierwszy poziom ale na początku muszę opanować pierwszy poziom. Co do użycia Case to będę miał konkretne fragmenty to pewnie użyje tej pętli.
artuross
Uzyj roznych funkcji, ktore zaleznie od wystepujacego znaku, beda sie do siebie odnosic.
Chodzi o to, by nie zaglebiac sie w nie-wiadomo-ile-if'ow. Jedna funkcje realizuje konkretna operacje, przy czym caly czas korzysta z jednego 'pointera' do konkretnej wartosci.
I tak, masz string 'string-1 { string-2 { string-3|string-4}}'
Wykonujesz petle i za kazdym razem, gdy znak jest rozny od {}| to wywolujesz funkcje string, ktorej przekazujesz znak, i tablice z wartosciami.
Gdy znak jest rowny { to musisz w obecnej tablicy utworzyc kolejna, wiec po prostu przekazujesz tablice i zamieniasz ja na tablice.
Gdy znak jest rowny | to pobierasz key aktualnego elementu i tworzysz nowy element (ten key musisz gdzies zapisac, zeby sie pozniej do niego odnosic, albo mozesz stworzyc referencje do niego i zapisac w jakiejs-tam-zmiennej-ktora-zawsze-jest-uzywana.
Jesli znak jest } to 'zamykasz', aktualna petle i przechodzisz do nastepnego elementu w tablicy wyzej warstwowo (i tutaj juz pisalem, caly myk polega na tym, by dobrze wykonac ten element, reszta nie ma znaczenia).


Opcja alternatywna, ktora teraz przyszla mi do glowy to zliczenie wszystkich utworzenie podciagow, tzn. najpierw wyciagasz najbardziej zewnetrzne ciagi (np. mozesz zliczyc wszystkie {, nastepnie }, i gdy ich roznica bedzie rowna 0 to zapisujesz calosc pomiedzy tymi dwoma do kolejnego elementu tablicy). Pozniej robisz to samo z ciagami, ktore powstaly, itd., itd., az ilosc wykonanych operacji bedzie rowna 0, wtedy przerywasz wykonywanie.
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.