Глобальная замена текста на сайте

Решилcя на днях перенести таки свой самый первый блог с Joomla на Drupal. В принципе ничего сложного тут нет, благо за нас уже постарались создатели модуля Joomla to Drupal который вполне успешно портирует материалы, а во-второй версии еще и комментарии, если они сохранены с использованием популярного Joomla расширения JComments.

Так вот портирование прошло успешно, хотя есть маленькие глюки. Рекомендую портировать сначала материалы, а следом комментарии. У меня при портировании комментариев с первого раза только часть проскочила без проблем, а некоторая часть обозначилась ошибкой. Решить эту проблему удалось выполнив портирование повторно, с установкой галочки Update existing. Здесь уточню, что если повторно импортировать и ноды, то будут созданы новые ревизии материалов, а это существенно утяжелит базу, что нам даром не надо.

Поскольку на Joomla я использовал их местный CCK компонент — JSEBLOD, текст материалов оказался подпорчен тэгами данного компонента. Естественно такой вид для друпала никуда не годился. Нужно было вырезать весь этот хлам.

Сначала я хотел воспользоваться найденым на d.org расширением Search and Replace Scanner  но, почитав список багов, понял, что ничего не выйдет. Стало понятно, что единственное решение — замена напрямую через MySQL. Готовое решение подсказал xandeadx. Выглядит оно так:

  1. SET @from_str = 'то что меняем', @to_str = 'то на что меняем';
  2. UPDATE `field_data_body` SET
  3.   `body_value`   = REPLACE(`body_value`,   @from_str, @to_str),
  4.   `body_summary` = REPLACE(`body_summary`, @from_str, @to_str);
  5. UPDATE `field_revision_body` SET
  6.   `body_value`   = REPLACE(`body_value`,   @from_str, @to_str),
  7.   `body_summary` = REPLACE(`body_summary`, @from_str, @to_str);

Но таким образом можно удалить только ненужный мусор, что же делать с хитрыми вставками Джумлы, например, в отличие от Друпала, короткий текст (анонс) там отделяется тэгом <!--break--> и является частью основного текста. При конвертации анонс отделился как надо, но одновременно остался и в тексте. А там он нам не нужен. Но как его удалить, ведь там в кажом материале уникальный текст,  а функции REGEXP_REPLACE в MySQL нет. Придется как то обойти это, например, вот так:

  1. UPDATE `field_data_body` SET `body_value` = SUBSTRING_INDEX(`body_value`, "<!--break-->", -1)
  2. WHERE `body_value` REGEXP ('<!--break-->');
  3.  
  4. UPDATE `field_revision_body` SET `body_value` = SUBSTRING_INDEX(`body_value`, "<!--break-->", -1)
  5. WHERE `body_value` REGEXP ('<!--break-->');

Так же приведу вам один сложный и интересный пример, найденый в сети:

Дано: в столбце типа text таблицы MySQL хранится текст, состоящий из строк (возможно список). Как удалить одну из строк этого списка, начинающуюся на префикс blablabla_

Решение: используем string-функции. Если текстовое поле col состоит из логических частей: до_искомой_строки + искомая_строка + после_искомой_строки

col = col_part_before + target_string + col_part_after

col_part_before — это все символы до первого вхождения префикса blablabla_
col_part_after — все символы после первого \n, который следует после первого префикса

то запрос будет таким:

UPDATE tbl SET col = CONCAT(col_part_before, new_string_or_empty, col_part_after) WHERE col REGEXP ("\n?blablabla_")

Фильтр WHERE не обязателен, но сильно ускорит выполнение запроса тем, что отсеет не нужные входные строки.

Вот готовый пример

  1. UPDATE tbl SET col = CONCAT (
  2.     SUBSTRING_INDEX(col, "blablabla_", 1),
  3.     "замена, если не нужна, то этот аргумент функции не пишем\n",
  4.     SUBSTRING(col, LOCATE("\n", col, LOCATE("blablabla_", col)) + 1)
  5. )
  6. WHERE col REGEXP ("\n?blablabla_")

Если исходных строк в тексте несколько, то запрос следует запустить многократно