Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: preg_replace z wykluczeniami?
Forum PHP.pl > Forum > PHP
marrrecki
Muszę napisać maszynkę do synonimów, która będzie działała tak, że w stringu:
  1. $str = 'Ta książka jest naprawdę super';

odszuka wyraz "książka" i zamieni go na "{książka|podręcznik}", ale jeżeli string:
  1. $str = 'Ta {książka|podręcznik} jest naprawdę super';
ponownie przepuszczę przez preg_replace to już nie zamieni mi wyrazu "książka", bo ten znajduje się w nawiasie klamrowym. Mam coś takiego:
  1. function str_replace_word($needle,$replacement,$haystack){
  2. $pattern = "/\b$needle\b/i";
  3. $haystack = preg_replace($pattern, $replacement, $haystack);
  4. return $haystack;
  5. }

ale brakuje jeszcze tych wykluczeń. Ma ktoś pomysł jak to poprawnie zrobić?

Rozwiązałem problem, jednak nie przy użyciu funkcji z tematu. Poniżej rozwiązanie jakby ktoś potrzebował:

  1. function strallpos($haystack,$needle,$offset = 0){
  2. $result = array();
  3. for($i = $offset; $i<strlen($haystack); $i++){
  4. $pos = strpos($haystack,$needle,$i);
  5. if($pos !== FALSE){
  6. $offset = $pos;
  7. if($offset >= $i){
  8. $i = $offset;
  9. $result[] = $offset;
  10. }
  11. }
  12. }
  13. return $result;
  14. }
  15.  
  16. $keywords = array('drzewo', 'test', 'krzak');
  17. $synonyms = array('{drzewo|drzewko|krzak}', '{test|tescik}', '{krzew}');
  18. $text = "{test|tescik} testowo test. {krzak|krzew}, drzewo, onegdaj<br>";
  19. echo $text;
  20. $i=0;
  21. for($i=0, $n=sizeof($keywords); $i<$n; $i++){
  22. $pos_arr = strallpos($text, $keywords[$i]);
  23. $j=0;
  24. for($j=0, $m=sizeof($pos_arr); $j<$m; $j++){
  25. if($text[$pos_arr[$j]-1] == '{' || $text[$pos_arr[$j]-1] == '|' || $text[$pos_arr[$j]+strlen($keywords[$i])] == '|' || $text[$pos_arr[$j]+strlen($keywords[$i])] == '}'){
  26. $allow_change = false;
  27. } else {
  28. if(($pos_arr[$j] == 0 && ($text[$pos_arr[$j]+strlen($keywords[$i])] == ' ' || $text[$pos_arr[$j]+strlen($keywords[$i])] == ',' || $text[$pos_arr[$j]+strlen($keywords[$i])] == '-' || $text[$pos_arr[$j]+strlen($keywords[$i])] == '&' || $text[$pos_arr[$j]+strlen($keywords[$i])] == '.')) ||
  29. ($text[$pos_arr[$j]-1] == ' ' && ($text[$pos_arr[$j]+strlen($keywords[$i])] == ' ' || $text[$pos_arr[$j]+strlen($keywords[$i])] == ',' || $text[$pos_arr[$j]+strlen($keywords[$i])] == '-' || $text[$pos_arr[$j]+strlen($keywords[$i])] == '&' || $text[$pos_arr[$j]+strlen($keywords[$i])] == '.')) ||
  30. ($text[$pos_arr[$j]-1] == ';' &&($text[$pos_arr[$j]+strlen($keywords[$i])] == ' ' || $text[$pos_arr[$j]+strlen($keywords[$i])] == ',' || $text[$pos_arr[$j]+strlen($keywords[$i])] == '-' || $text[$pos_arr[$j]+strlen($keywords[$i])] == '&' || $text[$pos_arr[$j]+strlen($keywords[$i])] == '.'))){
  31. $allow_change = true;
  32. } else {
  33. $allow_change = false;
  34. }
  35. }
  36. if($allow_change){
  37. $text = substr_replace($text, $synonyms[$i], $pos_arr[$j], strlen($keywords[$i]));
  38. }
  39. }
  40. }
  41. echo $text;
amii
Wielkie dzięki za ten kod być może mi się przyda. Potrzebny mi synonimizer tylko chciałem go dołączyć do programu generującego i wysyłającego artykuły do blogów opartych na wordpress.

Zastanawiam się jak by tą funkcję można zintegrować z systemem opartym na bazie danych. Najlepiej w założeniu byłoby jeśli user pisałby tekst w formularzu a następnie program na podstawie danych w bazie znajdował i losował synonimy w pełni automatyczny sposób. Mogłoby to wyglądać tak:

  1. CREATE TABLE `synonim` (
  2. `id` int(11) NOT NULL AUTO_INCREMENT,
  3. `wyrazy` varchar(255) NOT NULL DEFAULT '',
  4. PRIMARY KEY (`id`),
  5. ) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;
  6.  
  7. INSERT INTO `synonim` (`id`, `wyrazy`) VALUES (NULL, drzewo|drzewko|krzak),
  8. (NULL, test|tescik),
  9. (NULL, krzew|krzak)


Następnie trzeba by podpiąć akcję pod formularz, która by wyszukiwała w tekście synonimy:

  1. function losuj_synonim($text) { //w $text trzeba przekazać tekst z formularza czyli wywolujemy np. losuj_synonim($_POST['text'])
  2. $sql = "SELECT * FROM synonim"; //pobieramy całą listę synonimów z bazy
  3. $zapytaj = mysql_query($zapytanie) or die('Błąd w zapytaniu o tresci : ' . mysql_error());
  4.  
  5. while($row = mysql_fetch_array($zapytaj)) {
  6. $pojedynczy = explode('|', $row['wyrazy']); //tabela z synonimami
  7. $indeks = mt_rand(0, count($pojedynczy)); //losujemy indeks dla synonimu
  8. $a = true; //zmienna kontrolna
  9.  
  10. foreach ($pojedynczy as $key => $value) {
  11. if (strpos($text, $value) && $a) { //jesli znajdziemy ktorykolwiek z synonimow w tekscie......
  12. $text = str_replace($value, $pojedynczy[$indeks], $text); //nadpisujemy tekst z podmienionym synonimem
  13. if($value == $pojedynczy[$indeks]) continue; //jesli zamienilismy na to samo to powtarzamy, musze sprawdzic czy to sie nie zapetli
  14. else $a=false; //w innym przypadku ustawiamy zmienna kontrolna a na false zeby przerwac petle oznaczyc udana zamiane i nie zamieniac caly czas tego samego wyrazu na rozne synonimy
  15. }
  16. else break; //jesli a==FALSE lub nie znlezlismy synonimu w tekscie to wychodzimy z petli foreach
  17. }
  18.  
  19. return $text; //zwracamy podmieniony tekst i przekazujemy zmienna do innej funkcji np. dodajacej podmienione artykuly do blogow
  20. }
  21. }


Czy to zadziała nie wiem niedługo sprawdzę ten kod i najwyżej poprawię bo to pisałem z palca.
Drugi problem to efektywność tego typu narzędzia przy 3 synonimach to jest OK ale jak np. będę miał listę 3 tys. synonimów każdy średnio po 3 znaki do tego tekst o długości 3000 znaków to już może być kiepsko bo mamy podwójne zapętlenie, operacje bazie, ciągach znaków. Jeśli ktoś ma jakieś sugestie to chętnie posłucham smile.gif
marrrecki
A nie lepiej stworzyć bazę taką:
  1. CREATE TABLE `synonyms` (
  2. `id` int(11) UNSIGNED NOT NULL AUTO_INCREMENT,
  3. `fraza` varchar(255) NOT NULL,
  4. `synonim` varchar(255) NOT NULL,
  5. PRIMARY KEY (`id`)
  6. )

Dzięki temu do bazy wysyłasz tylko jedno zapytanie o wszystkie frazy i ich synonimy, wrzucasz je do tablic, które później są przetwarzane. Ja tego skryptu używam z połączeniem przez ajax (dokładnie jQuery), więc klient może sobie patrzeć na animację, a nie odświeżać stronę.
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.