![]() |
![]() |
![]()
Post
#1
|
|
Grupa: Zarejestrowani Postów: 183 Pomógł: 0 Dołączył: 19.05.2007 Ostrzeżenie: (0%) ![]() ![]() |
Witam. Mam pewną zagwostkę. Powiedzmy, że mam taki tekst:
Jakie wyrażenie zastosować, by zostawić tylko 1/2/3/4/X linki w tym tekście, a pozostałe zlikwidować i zostawić tylko tekst pomiędzy <a></a> ? Oczywiście przyjmując, że:
Czyli np dla "pseudofunkcji" zostaw_linki(2) efekt (dla tekstu powyżej) byłby:
Ten post edytował barat 8.12.2009, 10:11:14 |
|
|
![]() |
![]()
Post
#2
|
|
Grupa: Moderatorzy Postów: 4 362 Pomógł: 714 Dołączył: 12.02.2009 Skąd: Jak się położę tak leżę :D ![]() |
1. Najpierw policz ile tych linków jest (choćby preg_match_all)
2. Jeśli mieści się w limicie - zostaw tekst 3. Jeśli nie, musisz znaleźć zamknięcie ostatniego dozwolonego i cały tekst za nim pozbawić tagów A. Wydaje się proste? Nie do końca tak jest. Wszystko dlatego, że tylko str_replace posiada parametr OFFSET. Najwygodniejszy zaś jest preg_replace, który go nie posiada.. Na dodatek musisz przechwycić pozycję zamknięcia, do czego funkcje wyrażeń regularnych nie są przystosowane. Musisz zrobić własną funkcję robiącą to wszystko. Przydają Ci się: preg_replace, stripos, ale jest to jak najbardziej wykonalne i łatwe jeśli się zastanowisz jak użyć podanych przeze mnie funkcji (IMG:style_emoticons/default/smile.gif) Ten post edytował thek 8.12.2009, 11:10:26 |
|
|
![]()
Post
#3
|
|
Grupa: Zarejestrowani Postów: 253 Pomógł: 29 Dołączył: 18.08.2008 Ostrzeżenie: (0%) ![]() ![]() |
Przychodzi mi do głowy improwizacja kombinacją preg_split i preg_grep.
|
|
|
![]()
Post
#4
|
|
Grupa: Moderatorzy Postów: 4 362 Pomógł: 714 Dołączył: 12.02.2009 Skąd: Jak się położę tak leżę :D ![]() |
Zarzucę jak ja to widzę algorytmem (IMG:style_emoticons/default/smile.gif)
1. Wykonaj w pętli: a) znajdź w stringu pozycję </a> (IMG:style_emoticons/default/cool.gif) dodaj do znalezionej pozycji długość </a> c) wykonaj tyle razy ile masz w limicie linków. 2. Używając wyrażeń regularnych w pozostałej reszcie usuń znaczniki A wraz z atrybutami, zostawiając treść. Ale można prościej (IMG:style_emoticons/default/smile.gif) 1. Podziel string na tablicę używając jako delimitera </a> i dając jej maksymalnie LIMIT+1 elementów 2. Jeśli wynikowa tablica ma mniej niż LIMIT+1 elementów zostaw w spokoju. 3. Z ostatniego elementu tablicy usuń wszystkie A z atrybutami, pozostawiając jednak treść pomiędzy tagami A 4. Scal tablicę używając do łączenia </a> Drugi choć wydaje się dłuższy powinien być szybszy i prostszy w implementacji (IMG:style_emoticons/default/smile.gif) |
|
|
![]()
Post
#5
|
|
Grupa: Zarejestrowani Postów: 1 332 Pomógł: 294 Dołączył: 12.10.2008 Skąd: Olkusz Ostrzeżenie: (0%) ![]() ![]() |
preg_replace_callback - użyj tej słusznej funkcji, wyrażenie regularne daj uniwersalne na cały link, jako callback zastosuj funkcję "sterownik" która musisz napisac (najlepiej obiektowo) i musisz zliczać wystąpienia danego wyrażenia, a potem wewnątrz zdecydować co chcesz zrobić/zwrócić bądź przekierować na inną funkcję - masz drobne przykłady w manualu tam gdzie podałem link
pozdro... ps. niektórzy słabo szukają więc od razu daję jeszcze link (choć jest on też na podanej wyżej stronie): callback - masz tam przykłady wywoływania funkcji, także obiektowych - jako, że nie jestem zwolenikiem klas statycznych choć czasem się przydają od razu zacytuję: Cytat // Type 3: Object method call $obj = new MyClass(); call_user_func(array($obj, 'myCallbackMethod')); Ten post edytował zegarek84 8.12.2009, 11:56:53 |
|
|
![]()
Post
#6
|
|
Grupa: Moderatorzy Postów: 4 362 Pomógł: 714 Dołączył: 12.02.2009 Skąd: Jak się położę tak leżę :D ![]() |
Zegarek... Też o tym myślałem, ale gdzie przechowasz licznik tego callbacka? Jakaś zmienna statyczna? Bo przecież po wyjściu ze sterownika licznik zginie. Można kombinować z opisanym w komentarzach delayed curryingiem (opóźnionym dołączaniem?), ale moim zdaniem zastosowanie prostszych funkcji powinno dać lepszy rezultat.
Łatwiej zrobić explode, if, preg_replace na ostatnim elemencie i implode, niż kombinować jak napisać callback dla preg_replace_callback by licznik był zmienna globalną dla callbacka (IMG:style_emoticons/default/smile.gif) |
|
|
![]()
Post
#7
|
|
Grupa: Zarejestrowani Postów: 1 332 Pomógł: 294 Dołączył: 12.10.2008 Skąd: Olkusz Ostrzeżenie: (0%) ![]() ![]() |
podałem przykąłd jak użyć callback do obiektów bez zmiennych statycznych/globalnych ;p - obiektowo najłatwiej napisać sterownik (gdzie to tylko zestaw funkcji z if else...), używając funkcji preg_replace_callback text przeszuka tylko raz...
co prawda nie z linkami ale pisałem coś bardziej złożonego raz i jest to świetna sprawa - preg_replace_callback wypada też deczko szybciej niż sam preg_replace jeśli nic się nie robi - pisze o tym w manualu (choć dawno to czytałem i nie pamiętam gdzie - podejrzewam, że na stronie funkcji (IMG:style_emoticons/default/winksmiley.jpg) ) ps. preg_replace_callback przekazuje do funkcji callback bodajże tylko jeden parametr - znalazłem jeden swój skrypcik... co ważniejsze ten parametr jest tablicą - tak więc pisząc funkcję callback niech wewnątrz niej zrobi print_r($wejsciowa_zmienna); by zobaczyć gdzie co siedzi - zależy to od skonstruowanego wyrażenia regularnego (czyli w zasadzie tak jak w preg_match) poza tym inne dosyć fajne rozwiązanie ale na starcie jeśli nigdy tym się nie "bawił" jest przeszukanie tego tekstu przez DOM - ale na razie to rozwiązanie odradzam jeśli nigdy się nim nie bawił gdyż zrozumieć Mu go będzie ciężej (IMG:style_emoticons/default/winksmiley.jpg) Ten post edytował zegarek84 8.12.2009, 12:25:10 |
|
|
![]()
Post
#8
|
|
Grupa: Moderatorzy Postów: 4 362 Pomógł: 714 Dołączył: 12.02.2009 Skąd: Jak się położę tak leżę :D ![]() |
Jeśli nie bazujemy na żadnym ograniczaniu to owszem, callback może być użyty, ale do zwykłego usuwania tagu określonego - przerost formy nad treścią (IMG:style_emoticons/default/winksmiley.jpg) Sam preg_replace to potrafi. Zauważ jednak, że funkcja wywoływana jest za każdym znalezieniem elementu pasującego do wzorca. Musi więc siła rzeczy wiedzieć ile razy została już wywołana, a to bez jakiejś zmiennej statycznej czy globalnej jest nie do osiągnięcia, bo niby jak? Albo więc musi się odnosić do jakiejś statycznej, albo licznik wrzucasz jej jako parametr w argumentach. Oczywiście parametr musi być referencją, bo musisz go inkrementować wewnątrz funkcji i zwykłe wstawienie zmiennej nic nie da, bo utworzy ewentualnie kopię lokalną tej zmiennej, zapominaną po zakończeniu funkcji. Co będzie ostatecznie lepsze? Zależy od ilości i umiejscowienia linków w tekście. W obu ostatecznie jest używana_preg_replace (przypadek gdy osiągnięto tablicę LIMIT+1 elementową) albo wersja callbackowana i różnice nie powinny być ogromne. IMHO jednak dla ilości linków do LIMIT-1 szybsze będzie explode, if, implode niż preg_match_callback. Od LIMIT powinno być to zbliżone.
|
|
|
![]()
Post
#9
|
|
Grupa: Zarejestrowani Postów: 1 332 Pomógł: 294 Dołączył: 12.10.2008 Skąd: Olkusz Ostrzeżenie: (0%) ![]() ![]() |
...Zauważ jednak, że funkcja wywoływana jest za każdym znalezieniem elementu pasującego do wzorca. Musi więc siła rzeczy wiedzieć ile razy została już wywołana, a to bez jakiejś zmiennej statycznej czy globalnej jest nie do osiągnięcia, bo niby jak? Albo więc musi się odnosić do jakiejś statycznej, albo licznik wrzucasz jej jako parametr w argumentach. Oczywiście parametr musi być referencją, bo musisz go inkrementować wewnątrz funkcji i zwykłe wstawienie zmiennej nic nie da, bo utworzy ewentualnie kopię lokalną tej zmiennej, zapominaną po zakończeniu funkcji... przyznaj się szczerze, że nie czytałeś tego co pisałem ;p - zmienne globalne (IMG:style_emoticons/default/questionmark.gif) , zmienne statyczne (IMG:style_emoticons/default/questionmark.gif) parametr w argumentach (IMG:style_emoticons/default/questionmark.gif) - tfu tfu - nie po to specjalnie jakby nie mógł doczytać do linków podawałem link do callback i przykład użycia obiektu normalnego - tzn nie statycznego ;p Sam preg_replace to potrafi... sam str_replace to potrafi - wyrażenia regularne (IMG:style_emoticons/default/questionmark.gif) - czyż nie przerost formy nad treścią (IMG:style_emoticons/default/questionmark.gif) (IMG:style_emoticons/default/tongue.gif) - wszystko zależy od logiki aplikacji... ....W obu ostatecznie jest używana_preg_replace (przypadek gdy osiągnięto tablicę LIMIT+1 elementową) albo wersja callbackowana i różnice nie powinny być ogromne. IMHO jednak dla ilości linków do LIMIT-1 szybsze będzie explode, if, implode niż preg_match_callback. Od LIMIT powinno być to zbliżone. po primo to pisałem o funkcji preg_replace_callback a nie o preg_match_callback ;P , poza tym akurat czym mniejszy limit tym więcej do zamieniania ;P - i raczej rzekłbym , że jest odwrotnie (aczkolwiek nigdzie nie pisałem, że tak będzie najszybciej - tak będzie najwygodniej) - skoro tak piszesz to sądzę, że zrobiłeś jakieś testy (IMG:style_emoticons/default/questionmark.gif) (IMG:style_emoticons/default/haha.gif) |
|
|
![]()
Post
#10
|
|
Grupa: Zarejestrowani Postów: 183 Pomógł: 0 Dołączył: 19.05.2007 Ostrzeżenie: (0%) ![]() ![]() |
Dla potomnych będzie - działa (IMG:style_emoticons/default/biggrin.gif)
Pomysł fajny - nie mój, odpowiedź na innym forum (IMG:style_emoticons/default/smile.gif) |
|
|
![]()
Post
#11
|
|
Grupa: Zarejestrowani Postów: 1 332 Pomógł: 294 Dołączył: 12.10.2008 Skąd: Olkusz Ostrzeżenie: (0%) ![]() ![]() |
tyle, że dając odrazu gotowca nic się nie nauczysz ;P - na tym forum pomagamy a nie dajemy gotowce
PS - PORÓWNAJ SZYBKOŚĆ:
Ten post edytował zegarek84 8.12.2009, 23:17:26 |
|
|
![]()
Post
#12
|
|
Grupa: Zarejestrowani Postów: 183 Pomógł: 0 Dołączył: 19.05.2007 Ostrzeżenie: (0%) ![]() ![]() |
EDIT:
======================= Ok ... jednak już wszystko OK (IMG:style_emoticons/default/smile.gif) ======================= Postanowiłem się "pobawić" tym co napisałeś. Chciałem zamienić Twoje wyrażenie regularne na takie, które wyłapuje tylko linki zewnętrzne + nie będące z konkretnych domen np domena.pl, domena1.com Czyli: * http://www.wp.pl - wyczuj * http://wp.pl - wyczuj * www.wp.pl - wyczuj * /katalog/plik.ext - ignoruj * http://domena.pl -ignoruj * http://www.domena.pl -ignoruj * http://www.domena.pl/kontroler/metoda/ -ignoruj * www.domena.pl -ignoruj Wyszedł mi taki potworek: Kod <a[^\>]+href="(http://www\.|http://|www\.)(?!((www\.)?(domena\.pl|domena1\.com)))[^"]+"([^\>]+)?>([^\<]+)</a> Wklepanie tego w preg_match_all działa bez problemu.
jednak użycie tej regułki w Twojej klasie (zamieniając $vars[0]:$vars[1]; na $vars[0]:$vars[6](IMG:style_emoticons/default/winksmiley.jpg) nie działa ... zgłupiałem :/ Teoretycznie powinno zachować się tak samo... różnica między wyrażeniami jest taka, że moje zwraca 7 elementów zamiast dwóch ...
vs
Ten post edytował barat 18.12.2009, 13:11:14 |
|
|
![]() ![]() |
![]() |
Aktualny czas: 29.09.2025 - 20:16 |