# Using Regex with Watched Words

**URL:** https://meta.discourse.org/t/using-regex-with-watched-words/241861
**Category:** Site Management
**Tags:** reference, regex, watched-words, content
**Created:** [October 13, 2022, 7:01pm UTC](https://meta.discourse.org/t/using-regex-with-watched-words/241861 "2022-10-13T19:01:36Z")
**Posts on this page:** 2
**Page:** 1

<div class="post-metadata">

### Author: ![Discourse](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/discourse/32/148734_2.png) [@Discourse](https://meta.discourse.org/u/Discourse)
#### Post date: [October 13, 2022, 7:01pm UTC](https://meta.discourse.org/t/using-regex-with-watched-words/241861/1 "2022-10-13T19:01:37Z")

</div>

> 🔖 This topic explains how to effectively use regular expressions (regex) within Discourse’s [Watched Words](https://meta.discourse.org/t/watched-words-reference-guide/241735) feature.
> 
> :discourse: For sites on our hosting, these settings are hidden. Customers on paid hosting plans may contact our support team at `team@discourse.org`, to request regex with Watched Words.  
> **Note** : This feature is not available on our Free hosting plan.

Regular expressions (regex) are a powerful tool for defining search patterns. You can use regex in the [Watched Words](https://meta.discourse.org/t/watched-words-reference-guide/241735) feature to enhance the accuracy and flexibility of word filtering on your Discourse site.

> ℹ To use regular expressions (regex) in watched words you must first turn on the `watched_words_regular_expressions` site setting.

> ⚠ Regex is extremely powerful and thus dangerous. An incorrectly written regex statement can cause issues for your users. Test your regex statements on non-production instances before going live.

## Example Regex patterns

Here are some common regex patterns and how they can be employed:

### Case-insensitivity

By default, Discourse matches both uppercase and lowercase forms of a word.

> `thread`

This will match `thread`, `THREAD`, and `thReAd`.

### Character alternatives

Use character alternatives to expand your matches.

> `(t|7)hr(3|e)(4|a)d`

This will match all of the cases above, plus `thr3ad`, `7hread`, and `thr34d`.

> `threads?\b`

This will match `thread` and `threads` but not `threaded` or `threading`.

### Word boundaries

Regex patterns can unintentionally match parts of words. Use word boundaries to avoid partial matches.

```plaintext
\bthreads?\b

```

This matches `thread` and `threads` but avoids matches like `threadlike` or `unthreading`.

### Handling Unicode characters

Standard word boundaries may fail with Unicode characters. Create boundaries for characters not handled well by JavaScript regex.

> `gr(ü|ue)(ß|ss)e`

This matches all commonly spelled forms of the word grüße — including `gruesse` and `GRÜSSE`

Say you want to block the word `Über`, but not `Übersicht`. Using word boundaries like `\b(ü|ue)ber\b` doesn’t work because some of the JavaScript regex word flags don’t handle Unicode characters. Instead you have to make your own boundaries.

> `(?:^|\s)(ü|ue)ber\b`

This will now appropriately match `Über` and `ueber`, but not `Übersicht` or `uebersicht`.

### Catching deliberate character substitutions

To catch words where users substitute numbers or special characters for letters:

```plaintext
\bp[a@]ssw[o0]rd\b

```

This matches: `password`, `p@ssword`, `passw0rd`, `p@ssw0rd`, but not `mypassword` or `password123`

### Handling characters with punctuation in between

To catch attempts to evade filters by inserting punctuation:

```plaintext
\bs\W*p\W*a\W*m\b

```

This matches: `spam`, `s.p.a.m`, `s-p-a-m`, but not `s_p_a_m` (underscore is a word character), `spammy`, or `myspam`

### Matching multiple word variations

For matching phrases that might appear with different word forms:

```plaintext
\b(contact|email|reach)( us| me)?\b

```

This matches: `contact`, `contact us`, `contact me`, `email`, `email us`, `email me`, `reach`, `reach us`, `reach me`

### Detecting email patterns

To catch generic email address patterns:

```plaintext
\b[\w.%+-]+@[\w.-]+\.[a-zA-Z]{2,}\b

```

This matches: `user@example.com`, `my.name@sub.domain.co.uk`, `user+tag@domain.org`

### Finding hashtag variations

To match hashtags with different casing or slight variations:

```plaintext
\#(disc[o0]urse|f[o0]rum)\b

```

This matches: `#discourse`, `#DISCOURSE`, `#disc0urse`, `#forum`, `#f0rum`, but not `#discourseengine` or `#forums`

### Detecting repetitive patterns

To catch repeated characters that might indicate spammy content:

```plaintext
([a-zA-Z])\1{3,}

```

This matches: `aaaample`, `helllllo`, `yessssss`, detecting any letter repeated 4 or more times in a row

### Finding URLs with or without protocol

```plaintext
\b(?:https?:\/\/)?[\w-]+(\.[\w-]+)+\b

```

This matches: `example.com`, `sub.domain.org`, `https://discourse.org`, `http://meta.discourse.org`

### Avoiding nested character classes

**Correct:**

```plaintext
(hold)?

```

This correctly matches the optional word “hold”

Or if you want character alternatives:

```plaintext
[h][o0][l1][d]

```

This matches: `hold`, `h0ld`, `ho1d`, `h01d`

**Incorrect:**

```plaintext
[h[o0][l1]d]?

```

This incorrectly tries to nest character classes and will match any single character from `h`, `o`, `0`, `l`, `1`, or `d`, making it match words like `had`, `old`, etc.

### Using parentheses for optional words

**Correct:**

```plaintext
forum(s)?

```

This properly matches: `forum`, `forums`

**Incorrect:**

```plaintext
forum[s]?

```

This matches “forum” followed by an optional “s”, but uses a character class unnecessarily.

### Proper character class usage

**Correct:**

```plaintext
bad word

```

To match the phrase “bad word”

Or for a character class example:

```plaintext
[bB][aA][dD]

```

This matches: `bad`, `Bad`, `bAd`, `BAD`, etc.

**Incorrect:**

```plaintext
[bad word]

```

This matches any single character from `b`, `a`, `d`, `w`, `o`, `r`, or `d`, not the phrase “bad word”.

### Using quantifiers effectively

```plaintext
\b[0-9]{3,5}\b

```

This matches numbers with 3 to 5 digits: `123`, `1234`, `12345`, but not `12` or `123456`

For specific repeating patterns:

```plaintext
(spam){2,3}

```

This matches: `spamspam`, `spamspamspam`

### Applying word boundaries properly

**Without boundaries:**

```plaintext
free

```

This matches: `free`, `freedom`, `carefree`

**With boundaries:**

```plaintext
\bfree\b

```

This matches only: `free`, but not `freedom` or `carefree`

### Handling Unicode characters correctly

**Correct approach:**

```plaintext
(?:^|\s)(ö|oe)zel\b

```

This matches: `özel`, `oezel` at word boundaries, even with Unicode characters

**Incorrect approach:**

```plaintext
\bözel\b

```

This may not work correctly with the Turkish character ö.

## Additional Information

> ℹ You can test Regex expressions on [https://regex101.com/](https://regex101.com/). If you do so, ensure you switch the regex flavour to ECMAScript.

Regex capture group back-references (e.g., `\1` in replacement strings) are not supported in Watched Words replacement values. The replace and link actions do support regex for matching, but the replacement is always a literal string.

> Last edited by @dax 2026-04-29T12:15:04Z
> 
> > **Check document**
> >
> > Perform check on document:

---

<div class="post-metadata">

### Author: ![Burhan\_Qaddoumi](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/burhan_qaddoumi/32/424472_2.png) [@Burhan\_Qaddoumi](https://meta.discourse.org/u/Burhan_Qaddoumi)
#### Post date: [June 14, 2024, 6:03pm UTC](https://meta.discourse.org/t/using-regex-with-watched-words/241861/2 "2024-06-14T18:03:17Z")

</div>

Forgive my noobness, but I ~~was not able to find the site setting for `watched words regular expressions` anywhere. I also looked for `regex`, `regular expression`, and other variants, but didn’t find anything that looked like it would enable regex for watched words. Do you have the slug to the site settings where this could be enabled (cloud hosted instance)?~~

**EDIT** the answer was just above and found [here](https://meta.discourse.org/t/hidden-settings-on-discourse-hosted-sites/310574)
