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개의 좋아요
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
Replacing content in multiple topics with Regex?
Is there a way to easily replace the word "Topic" everywhere on my site at once
Youtube embeds missing
Bulk replacement in translated strings?
Shouldn't users be able to delete their accounts whenever they want?
Updating image URL's after a domain change
Tool to remove email addresses from posts
Fix quotes after phpBB import
Remove BBCode and convert to Markdown
Forum Link Checker
Switch from TAGS to TAG broke links in posts and "Delete Unused Tags"
Search and Replace a text string in the post database
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
Update URLs inside a poll after changing CDN
How to handle changing organizational roles, re. past mentions on the forum
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?

특정 카테고리 내의 주제들만 이 방식으로 처리하려면 어떻게 해야 하나요?

제 사용 사례는 가져온 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개의 좋아요

제이, 감사합니다! 그 방법이 딱 맞을 것 같아요.

적절하게 문제를 진단하고 상류(upstream)에서 수정이 있는지 확인해야 할 것 같습니다. 아니면 RSS Polling 플러그인에 무언가를 붙여야 할 수도 있는데, 이 플러그인은 다루기가 좀 까다로워요!

1개의 좋아요

추측이지만, RSS 피드로 생성된 게시물에서 다른 문제도 겪고 계신가요? 피드의 소스를 볼 때도 ? 문자가 나타나요? 아마 인코딩 문제인 것 같습니다.

2개의 좋아요

네, 지금 확인하고 있습니다. ?는 비정상적인 문자가 있을 때마다 항상 표시되므로, 이는 RSS 소스 측의 문제입니다. '가 가장 흔한 경우이지만, ā, " 및 기타 한두 개 문자에서도 동일한 문제가 발생하고 있습니다.

불행히도 관련 소프트웨어 회사가 Discourse 팀만큼 신속하게 대응하지는 않습니다 :kissing_heart:! 행운을 빕니다.

2개의 좋아요

저도 그렇게 의심하고 있었습니다. 올바른 인코딩을 더 잘 감지하는 것만으로 해결될 수도 있습니다.

3개의 좋아요

아래와 같이 대체할 수 있는 안내를 받을 수 있을까요?

[member=12345] → @

URL를 교체하는 데에는 이 예제가 잘 작동합니다. 하지만 문구(phrase)에는 작동하지 않습니다.

예시:

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와 레일즈 양쪽 모두에서 이스케이프를 처리해야 하기 때문입니다. 역슬래시를 여러 개 사용해 이스케이프를 처리할 수도 있겠지만(역슬래시 자체도 이스케이프해야 하므로), 실제로는 불가능할 가능성이 높습니다.

위에서 제시한 레일즈 예시를 확인해 보시고 이해가 되시는지 봐 주세요. 다음에 노트북이 있으면 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:이 여전히 포함된 게시물의 수를 쉽게 조회할 수도 있습니다.

네, 좀 이상하긴 해요. 같은 명령어를 두 번 세 번 더 실행해 봤는데, 매번 333개의 게시물이 더 재매핑됐어요… :question:

로그에는 여러 개의 대체(replacement) 항목이 표시되는데, 페이지를 새로고침하고 실제 게시물을 확인해 보면 아무런 변경이 없어요:

이건 캐시 문제인 것 같아서 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개의 좋아요

원본(raw)은 변경되었지만, (새) 게시물이 아직 생성(bake)되지 않은 것일 수 있나요?

저도 그 생각을 해봤는데, 아니요, 해당 게시물들의 편집 버튼을 눌렀더니 원본(raw)은 그대로였어요. 그리고 성공적으로 교체된 부분에서는 다시 구울(rebake) 필요 없이 새 이모지가 바로 나타났어요.

1개의 좋아요

수입된 YouTube 링크 600개 이상을 교체하려고 시도하고 있는데, 링크가 단독으로 한 줄에 있을 때만 작동하는 것 같습니다.

따라서 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

이런 거요? 마크다운에서 /를 쓰는 것이 CR/LF나 \n, 또는 <br /> 같은 것보다 더 나은 것 같다는 가정 하에요.

이걸 셸에서 어떻게 실행하나요? 그냥 "rails"를 입력한 뒤 코드를 붙여넣으면 되는 건가요?