Replace a string in all posts

:bookmark: This guide explains how to replace a string in all posts within a Discourse instance.

:person_raising_hand: Required user level: System Administrator

:warning: Console Access Required

Want to replace a string in all the posts on a site? Let’s get started!

:warning: WARNING: We strongly recommend you take a full backup before proceeding, and make sure your string replacement is specific enough to affect only the places you want it to. If this string replacement goes wrong, every post on your site will look broken!

Access your site

Start by accessing your Discourse instance via SSH and entering the Docker container:

cd /var/discourse
./launcher enter app

Performing string replacements

Basic case-sensitive replacement

To replace a string, use the following command. Replace find with the string to locate and replace with the desired substitution:

rake 'posts:remap[find,replace]'

Example results:

find —> replace
Find —> Find
FIND —> FIND
finders keepers —> replaceers keepers
finding —> replaceing

This method can be useful for tasks such as replacing emojis:

rake 'posts:remap[:slightly_smiling:,:slight_smile:]'

The above command will replace all occurrences of :slightly_smiling: with :slight_smile:.

Case-insensitive replacement

For replacements that ignore case sensitivity use:

rake 'posts:remap[find,replace,string,true]'

Example results:

find —> replace
Find —> replace
FIND —> replace
finders keepers —> replaceers keepers
finding —> replaceing

Regex replacement

For advanced replacements with regex, format the command accordingly:

rake 'posts:remap[(?<!\\w)(?=\\w)find(?<=\\w)(?!\\w),replace,regex]'

Example results:

replace —> replace
Find —> Find
FIND —> FIND
finders keepers —> finders keepers
finding —> finding

Deleting words or strings

To completely remove a word or string, apply these commands:

Basic case-sensitive deletion

rake 'posts:delete_word[word-to-delete]'

Case-insensitive deletion

rake 'posts:delete_word[word-to-delete,string,true]'

Regex deletion

rake 'posts:delete_word[\\[color=#[0-9a-fA-F]{3,6}\\],regex]'
70 лайков
Batch processing to search and replace in all posts
Global Replace across database
[Announce] Search & replace / batch process Discourse posts
How do I change the legacy CDN URLs of images in posts?
How to automatically replace a double exclamation point when a message is saved?
Administrative Bulk Operations
Updating image URL's after a domain change
Replacing content in multiple topics with Regex?
Forum Link Checker
Remove BBCode and convert to Markdown
Tool to remove email addresses from posts
Bulk replacement in translated strings?
Youtube embeds missing
Fix quotes after phpBB import
Is there a way to easily replace the word "Topic" everywhere on my site at once
Shouldn't users be able to delete their accounts whenever they want?
Watched words - replace link/url works in test but not in post
Permalink question (rewriting/redirecting old gallery contents)
Localised inline date/time
How to fix formatting issues? - markdown badly migrated to HTML
How to run rake posts:remap with domain?
Migrate a phpBB3 forum to Discourse
Discourse Doc Categories
What is rebaking and is it necessary when moving a server?
Discourse s3 backup folder
Pin more than one topic globally
After migrating from XenForo to Discourse
Hosted to self-hosted migration: past uploads still reference discourse infra
Trouble with `discourse remap` remapping `topic_links url`
CommonMark testing started here!
Remove images from PMs that have been inactive for >1 year
Masonry Image Gallery
Redirect Article- possible?
Upload links broken after S3 bucket change
How to search and replace URL instances throughout topics?
Enable a CDN for your Discourse
How do I move my s3 upload bucket from one provider to another?
Imgur images broken
Move from BackBlaze B2 to Digital Ocean Spaces
What's the fastest way to replace strings with multiple regexes in 1 million posts?
Too many user emails domains not working lead to mailgun domain disabled: what to do?
Renaming uploaded files
After rebuilding, avatar photos are missing
The change of from "tags" to "tag" in its URL affects my Discourse since they are linked in many posts. How can I automatically change them?
Switch from TAGS to TAG broke links in posts and "Delete Unused Tags"
Search and Replace a text string in the post database

Как бы я это сделал только для тем в одной категории?

Мой случай использования — импортированная RSS-лента, которая, к сожалению, отображает ? вместо '. А так как лента представляет собой новостную с большим количеством цитат, это становится проблемой!

1 лайк

Это нужно делать через Rails, и это будет сложно, так как сообщения не принадлежат категориям — темы принадлежат. Похоже, вам понадобится плагин, если это постоянная проблема. Вы можете использовать умный JOIN или просто перебирать их циклом, например:

Topics.where(category_id: 123).each do |t|
  posts.where(topic_id: t, post_number: 1).each do |p|
    if p.raw.match("?")
        p.raw.gsub!("?","'")
        p.save
    end
  end
end

Если проблема не только в post_number: , не включайте это условие.

Если сообщений не очень много, этого, вероятно, будет достаточно, если код вообще работает.

1 лайк

Спасибо, Джей! Это должно сработать отлично.

Мне нужно правильно устранить неисправность и посмотреть, есть ли исправление на стороне источника. Или, возможно, мне придётся добавить что-то к плагину RSS Polling, который является довольно хитрым зверем!

1 лайк

Только предположение, но видите ли вы какие-либо другие проблемы с постами, созданными из RSS-ленты? Присутствуют ли символы ?, когда вы просматриваете исходный код ленты? Мне интересно, не сталкиваетесь ли вы с проблемой кодировки.

2 лайка

Да, я как раз сейчас это проверяю. Символы ? появляются каждый раз, когда встречается необычный символ, значит, проблема на стороне источника RSS. Оказалось, что ' — самый частый случай, но это также происходит с ā, " и ещё с одним-двумя другими символами.

К сожалению, участвующая компания-разработчик реагирует не так оперативно, как команда Discourse :kissing_heart:! Пожелайте мне удачи.

2 лайка

Я тоже так подозревал. Возможно, дело в более точном определении правильной кодировки.

3 лайка

Пожалуйста, дайте рекомендации по замене, как указано ниже?

[member=12345] → @

Я использовал этот пример, который работает для замены URL-адреса. Однако он не работает для фраз.

Пример:

rake posts:remap["I Don't Want This Phrase","But I Do Want This One","string",true]

Я постоянно получаю эту ошибку:

ERROR: Expecting rake posts:remap['find','replace',type] where type is string or regex

Я также пробовал использовать одинарные кавычки, как показано в сообщении об ошибке, но безрезультатно. Даже попробовал заменить пробелы между словами на дефисы, как в примере с удалением слова. Это дало ту же ошибку.

Есть какие-нибудь советы?

Боюсь, что если вам нужно что-то сделать с кавычками, лучше всего это сделать в Rails. При использовании задачи Rake вам придется иметь дело с экранированием и в bash, и в Rails. Возможно, удастся использовать множество обратных слешей (которые тоже нужно экранировать), но, скорее всего, нет.

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

1 лайк

Спасибо за ответ. Это немного выше моего понимания, но я, конечно, могу научиться.

Похоже, что проблема возникла из-за кавычек в строке текста…

Моя задача: я часто меняю заголовки и URL-адреса своего блога, поэтому мне нужно возвращаться на форум и обновлять эти ссылки, заголовки и URL-адреса. Я вижу, что это может стать регулярной задачей при работе над SEO. Любые дополнительные детали были бы отличны.

1 лайк

Здесь что-то непонятное. Я пытаюсь заменить все вхождения :THUMBS-UP: на :+1: почти в 3 миллионах постов (включая личные сообщения). Я выполнил:
rake posts:remap[":THUMBS-UP:",":+1:"]
После примерно 50 минут вывода ................. команда вернула результат 40000 posts remapped!. Это число кажется подозрительно ровным. Я действительно нашёл некоторые вхождения, которые были заменены на :+1: как в недавних постах, так и в сообщениях многихлетней давности, но при этом осталось огромное количество :THUMBS-UP: даже в тех же темах, где уже есть успешные замены на :+1:.

Это действительно кажется немного странным. Вы пробовали переназначить снова?
Вы также можете легко получить количество постов, которые всё ещё содержат :THUMBS-UP:, используя data-explorer, если эта информация может быть полезна.

Да, это странно. Я попробовал запустить ту же команду dva ещё три раза, и каждый раз она переназначала по 333 сообщениям… :question:

В логе отображается множество якобы выполненных замен, однако при перезагрузке страницы и проверке самого сообщения оно остаётся без изменений:

Мне это показалось проблемой кэширования, поэтому я выполнил redis-cli flushall и сделал полную перезагрузку Discourse, но сообщения, которые в логе были помечены как отредактированные, всё равно не изменились.

Кроме того, в логе ошибок появилось множество сообщений вроде этих:
Screenshot from 2023-01-06 12-47-36

Вроде бы всё должно работать… но одна из проблем в том, что это выглядит так, будто можно экранировать и другие символы, например запятые, но на самом деле нельзя, поскольку кавычки обрабатываются оболочкой, а не парсером rake.

Например:

→ rake posts:remap["a,b","a+b"]
ERROR: Expecting rake posts:remap['find','replace',type] where type is string or regex

Кроме того, скобки тоже нужно экранировать, так как сами по себе они являются спецсимволами оболочки. Вы даже не сможете выполнить команду, если в каталоге есть файл с именем posts:remapa (маловероятно, но возможно) или если установлен параметр failglob.

Я думаю, нам стоит изменить эти команды — они вводят в заблуждение, потому что выглядят так, будто мы экранируем строки, которые нужно заменить, но на самом деле мы этого не делаем. Кавычки обрабатываются оболочкой; Rails их никогда не видит. Нет смысла вообще использовать кавычки, а если Rails их всё же увидит, они станут частью строки:

→ rake 'posts:remap["find","replace"]'
Are you sure you want to replace all string occurrences of '"find"' with '"replace"'? (Y/n)

Вот ещё несколько примеров, в том числе о том, как работать с запятыми и другими спецсимволами:

rake 'posts:remap[find,replace,string,true]'
rake $'posts:remap[string with a quote\',string without a quote]'
rake 'posts:remap[a\, b,a+b]'

хотя, что странно, это работает:

→ rake 'posts:remap[string with a bracket] either quoted\] or not,string without a bracket]'
Are you sure you want to replace all string occurrences of 'string with a bracket] either quoted] or not' with 'string without a bracket'? (Y/n)
1 лайк

Возможно, сырой текст изменён, но новый пост ещё не «запечён»?

Я тоже так подумал, но нет: я нажал кнопку «Изменить» в этих сообщениях, и исходный текст остался без изменений. А при успешной замене новое эмодзи появляется без повторной обработки.

1 лайк

Итак, я пытаюсь заменить более 600 вставок ссылок на YouTube, импортированных в текст, но, похоже, это работает только тогда, когда ссылка находится на отдельной строке.

Мне нужно вставить перенос строки перед самой ссылкой на YouTube. К счастью, у меня есть строка типа “replaceme”, которую можно заменить на перенос строки.

Какой способ вставки переноса строки в Ruby является правильным? Или переноса строки в Markdown?

Сработает ли что-то вроде этого?

rake posts:remap["replaceme","\n",string,true]

Или мне нужно экранировать \n несколько раз?

rake posts:remap["replaceme","\\\n",string,true]

Или мне стоит ориентироваться на перенос строки в Markdown (который, верно, представляет собой один обратный слэш)?

rake posts:remap["replaceme","\",string,true]

Наверное, это тоже нужно экранировать?

Любая помощь будет оценена по достоинству.

Я бы сделал это на Rails, где не нужно беспокоиться о стольких уровнях кавычек.

2 лайка

Хорошая идея. Экранирование вещей вызывает у меня головную боль.

Вижу, что ваш код выше достаточно прост. Что-то вроде этого?

Topics.where(category_id: 123).each do |t|
  posts.where(topic_id: t).each do |p|
    p.raw.gsub("replaceme","/")
  end
end

Что-то в этом роде? Я предполагаю, что markdown-слэш лучше, чем использование CR/LF или \n, или даже
или чего-то подобного?

Как запустить это из командной строки? Просто ввести “rails”, а затем скопировать туда код?