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]'

Last edited by @SaraDev 2024-11-14T00:39:05Z

Check documentPerform check on document:
「いいね!」 70

単一のカテゴリのトピックのみを対象にするにはどうすればよいですか?

私のユースケースは、インポートされたRSSフィードで、イライラすることに引用符の代わりに「?」が表示されることです。フィードは引用が多いニュースフィードなので、これは問題です!

「いいね!」 1

Railsから行うことになります。投稿はカテゴリに属さず、トピックが属するため、これは困難です。これが継続的な問題である場合は、プラグインが必要になるでしょう。結合を使用して賢く行うか、次のようにループすることができます。

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 Pluginに何かを追加する必要があるかもしれません!

「いいね!」 1

推測ですが、RSSフィードから作成された投稿で他に問題はありますか?フィードのソースを表示したときに「?」文字が表示されますか?エンコーディングの問題ではないかと考えています。

「いいね!」 2

はい、今見ています。「?」は、通常ではない文字があるたびに表示されます。したがって、RSSソース側に問題があります。「'」が最も一般的であることが判明しましたが、「ā」、「"」、その他1つか2つでも発生しています。

残念ながら、関与しているソフトウェア会社は、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

エラーメッセージに示されているように、単一引用符で試しましたが、うまくいきませんでした。単語間のダッシュも試しました。削除単語の例のように。同じエラーが発生しました。

何かアドバイスはありますか?

引用符を扱う必要がある場合は、レールで行うのが最善だと思います。Rakeタスクでは、エスケープのためにbashとレール(rails)の両方を処理する必要があります。バックスラッシュ(これもエスケープする必要があります)をたくさん使用できるかもしれませんが、おそらくできません。

私が上に示したレール(rails)の例を見て、それが理解できるかどうか確認してください。次にラップトップを手に入れたときに、OPに何かを追加するようにします。

「いいね!」 1

ご回答ありがとうございます。私の手に負えないようですが、学ぶことはできます。

問題の原因は、テキスト文字列内の引用符のようですね…

私の目的は、ブログのタイトルとURLを変更することです。そのため、フォーラムに戻ってそれらのリンク、タイトル、URLを更新したいのです。SEOに取り組む際には、これは半定期的なタスクになるでしょう。さらに詳しい情報があれば幸いです。

「いいね!」 1

ここが理解できていない点があるはずです。ほぼ300万件の投稿(プライベートメッセージを含む)全体で、:THUMBS-UP: の出現箇所を :+1: に置き換えようとしています。以下を実行しました。
rake posts:remap[\":THUMBS-UP:\",\":+1:\"]
そして、約50分間の ................. の後、40000 posts remapped! と返されました。これは疑わしいほど均一な数字のように思えます。最近の投稿と数年前の投稿の両方で :+1: に置き換えられた出現箇所を見つけましたが、成功した :+1: の置き換えがいくつかある同じトピック スレッドにも、:THUMBS-UP: が大量に残っています。

それは少し奇妙ですね。再マッピングを試しましたか?
この情報がお役に立つなら、:THUMBS-UP: を含む投稿の数を data-explorer を使用して簡単に返すこともできます。

ええ、奇妙ですね。同じコマンドをあと3回実行してみましたが、そのたびに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

YouTubeリンクの600以上のインスタンスを置き換えようとしていますが、リンクが単独の行にある場合にのみ機能するようです。

そのため、YouTubeリンクの前に改行を挿入する必要があります。「replaceme」という文字列があるので、それを改行に置き換えることができます。

Rubyの改行に適した方法はありますか?それともMarkdownの改行ですか?

このようなものでうまくいきますか?

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

それとも、\n を数回エスケープする必要がありますか?

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

Markdownの改行(バックスラッシュ1つで正しいですか?)を目指すべきでしょうか?

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

このような感じでしょうか?改行や <br /> などよりも、Markdown の / の方が良いと仮定してよろしいでしょうか?

これをシェルから実行するにはどうすればよいですか?「rails」と入力してから、コードを貼り付けるだけですか?