Как лучше оформить замены в тексте?

Приветствую.
Размышляю над тем, как сделать замены в тексте — слово заменить на ссылку. Надеюсь вы подскажете алгоритм. Есть несколько разных шаблонов и текст, в котором надо делать замены, размещен в разных блоках (в стандартных полях типа description и content, а также в дополнительных полях). Количество полей разное, зависит от шаблона — от двух до пяти. Мне понятно, вероятно я так думаю, что нужно взять все эти поля о объединить их в одно (добавить какой-нибудь разделитель), затем пройтись алгоритмом замены по объединенному тексту, а после разделить текст по разделителю и вернуть модифицированный текст в каждое поле.
Подскажите пожалуйста как конкретно это лучше всего реализовать?
weranda
05 сентября 2019, 10:02
modx.pro
1
862
0

Комментарии: 16

Павел Романов
05 сентября 2019, 10:57
0
Сделайте сниппет с логикой замены и используйте его в качестве модификатора.
Например, сниппет link:
<?php
// что меняем
$arr1 = array(
    '_ссылка1_',
    '_ссылка2_', 
    '_ссылка3_'
);
// на что меняем
$arr2 = array(
    '<a href="[[~1]]">ссылка1</a>', 
    '<a href="[[~2]]">ссылка2</a>', 
    '<a href="[[~3]]">ссылка3</a>'
);
return str_replace($arr1, $arr1, $input);

В шаблоне выводите:
[[*content:link]]
[[*description:link]]
    weranda
    05 сентября 2019, 11:06
    0
    Над этим вариантом размышлял. Если надо будет сделать только по одной замене слова на странице, то с прикреплением одного и того же модификатора к нескольким полям замены будут проведены минимум два раза на одной страницы при условии, что искомые для замены слова будут встречаться сразу в двух полях. Поэтому этот вариант не подходит.
      Павел Романов
      05 сентября 2019, 11:12
      0
      Сделайте свой сниппет для каждого поля или используйте опции:
      <?php
      switch ($options){
          case 1:
          // логика замены для поля 1
          $out = '...';
          break;
          
          case 2:
          // логика замены для поля 2
          $out = '...';
          break;
      }
      return $out;

      Вывод:
      [[*content:snippet=`1`]]
      [[*description:snippet=`2`]]
        weranda
        05 сентября 2019, 11:24
        0
        Малость не понял. Поясню что я имел в виду выше. Допустим, есть список замен из 100 слов. Мне без разницы где встретится слово — в первом поле, втором или третьем, но если оно есть на странице в любом из них, то должно быть заменено. Я так понял, что вы предлагаете каким-то образом разделить список замен так, чтобы для каждого из поля (content, dexctiption и пр.) не было пересечений в списках замен. Вы это предлагаете? Или же вы предлагаете добавлять дополнительную логику и в ней проверять были ли замены в предыдущем блоке для следующего?
          Павел Романов
          05 сентября 2019, 11:36
          0
          Я предложил второй вариант в ответ на Ваш комментарий про разные поля и он имеет смысл, если для content один набор замен, а для description другой.

          Если Вам все равно, в каком поле встретится слово, то это как раз первый вариант. Прописываете в нем замену 100 слов и при парсинге шаблона система их заменит там, где они встречаются.

          Можно вообще не привязываться к полям, а сделать плагин замены на событие OnWebPagePrerender и тогда будет обрабатываться вообще весь код страницы перед выводом в браузер.
            weranda
            05 сентября 2019, 11:57
            0
            Либо я не понимаю, либо плохо объяснил.
            Давайте попробую еще раз. Для примера возьмем всего два поля и две замены. В первом и во втором полях встречаются по два искомых для замены слова. Используя первый вариант (через один и тот же модификатор для каждого поля), в каждом из двух полей мы получим по две замены. Этот вариант не подходит, так как в нем должно было бы замениться только два первых совпадения, а они встречаются в первом поле. Во втором же поле замен не должно было быть, так как по одной из них уже сделано было в первом поле.
            Список замен один, общий для всех полей. Таким образом первый вариант не подходит из-за возможности повторения множественности замен, а второй — из-за того, что список замен общий для всех полей.
            Третий предложенный вами вариант с обработкой всего кода страницы тоже не подход, так как нужна обработка данных именно в некоторых полях, а не во всех.
              Павел Романов
              05 сентября 2019, 12:25
              0
              Да, честно говоря, непонятно )).

              Этот вариант не подходит, так как в нем должно было бы замениться только два первых совпадения, а они встречаются в первом поле
              В этом варианте заменятся все совпадения во всех полях. Модификатор вызывается по отдельности для каждого поля.

              То есть если у Вас в поле description такой текст:
              Lorem ipsum dolor слово1 sit amet, consectetur adipiscing слово2 elit.

              А в поле content такой:
              Lorem слово1 ipsum dolor sit amet, consectetur adipiscing слово2 elit слово3.

              То в результате работы сниппета:
              <?php
              $arr1 = array(
                  'слово1',
                  'слово2', 
                  'слово3'
              );
              $arr2 = array(
                  'замена1', 
                  'замена2', 
                  'замена3'
              );
              return str_replace($arr1, $arr1, $input);

              У Вас [[*description:snippet]] выведет:
              Lorem ipsum dolor замена1 sit amet, consectetur adipiscing замена2 elit.

              А [[*content:snippet]] выведет:
              Lorem замена1 ipsum dolor sit amet, consectetur adipiscing замена2 elit замена3.
                weranda
                05 сентября 2019, 12:42
                0
                Ладно, попробую еще раз объяснить.

                Имеем три поля:
                //Поле 1
                зима, весна, лето, осень
                
                //Поле 2
                весна и лето — теплые времена года
                
                //Поле 3
                зима и осень — прохладные времена года. пьем кофе.

                Имеем список замен (список будет исключительно в единичном экземпляре):
                зима —> зима (холод)
                весна —> весна (тепло)
                лето —> лето (тепло)
                осень —> осень (холод)
                кофе —> кофе (горячий)

                После преобразования должно получиться вот что:
                //Поле 1 (4 совпадения, 4 замены)
                зима (холод), весна (тепло), лето (тепло), осень (холод)
                
                //Поле 2 (4 совпадения, 0 замен, так как замены уже были)
                весна и лето — теплые времена года
                
                //Поле 3 (1 совпадения, 1 замена)
                зима и осень — прохладные времена года. пьем кофе (горячий).

                Т. е. должна быть только одна замена из списка замен по всем полям, если их объединить.
                  Павел Романов
                  05 сентября 2019, 12:54
                  0
                  Т. е. должна быть только одна замена из списка замен по всем полям, если их объединить.
                  Из Ваших предыдущих сообщений не очевидно, что замена должна срабатывать только один раз ))).

                  А так да — объединяйте все в один текст, делите, меняйте, потом пишите результат в плейсхолдеры и выводите на страницу.
                    weranda
                    05 сентября 2019, 13:03
                    0
                    Возможно, именно этот момент мне и непонятен. Как получить нужные поля, обработать их — это понятно, а вот потом как вывести все обработанное в одном месте в разные поля — вот это вопрос.
                      Павел Романов
                      05 сентября 2019, 13:27
                      0
                      Можно передавать сниппету поля:
                      [[Snippet? &fields=`content,description,tv.tvname`]]

                      В сниппете:
                      <?php
                      $inarr = explode(',', $fields); 
                      foreach($inarr as $field){
                          if(strpos($field, 'tv.') === false){
                              $content = $modx->resource->get($field);
                          }else{
                              $content = $modx->resource->getTVValue(str_replace('tv.', '', $field));
                          }
                      	$text[] = $content;
                      }
                      
                      $str = implode('--separator--', $text);
                      
                      $result = '.......'; // заменяем что надо
                      
                      $resarr = explode('--separator--', $result);
                      foreach($resarr as $key => $val){
                      	$modx->setPlaceholder('new.'.$inarr[$key], $val);
                      }
                      return;

                      Выводите на страницу:
                      [[+new.content]]
                      [[+new.description]]
                      [[+new.tv.tvname]]
                      weranda
                      05 сентября 2019, 13:38
                      0
                      weranda
                      05 сентября 2019, 13:39
                      0
                      Правильно ли я понял? — Сначала в шаблоне один раз перед нужными полями мы запускаем сниппет с именем Snippet, передаем в него нужные нам поля (content,description,tv.tvname). Затем сниппет запускается, включается прописанная в нем логика (делает замены) и закрепляет результат за некими переменными, именуемыми по именам переданных полей (content,description,tv.tvname). После этого в шаблоне становится доступными результаты работы сниппета, доступ к которым можно получить через общий префикс и имена, которые были заданы в сниппете.
                      Я просто никогда раньше с плейсхолдерами не сталкивался.
                      Павел Романов
                      05 сентября 2019, 13:41
                      0
                      Да, именно так.
                      weranda
                      05 сентября 2019, 13:50
                      0
                      Класс, спасибо за разъяснения.
                      Может быть у вас завалялась ссылочка на полезный материал по этим плейсхолдерам. Посмотрел информацию по ссылке, данной вами выше, — она скудна и без объяснений подобно вашим не разберешься.
                      Павел Романов
                      05 сентября 2019, 13:57
                      0
Авторизуйтесь или зарегистрируйтесь, чтобы оставлять комментарии.
16