Regex for Extracting Hashtags and Mentions from Text

Building a comment section, social feed, or content moderation tool almost always requires pulling out #hashtags and @mentions from free text. This guide covers the regex patterns, JavaScript's match and matchAll methods, and the Unicode edge cases that trip up naive patterns.

Basic Hashtag Extraction

const text = 'Loving the new #NextJS release! Also check out #WebDev and #AI tools.';
const hashtags = text.match(/#[\w]+/g);
console.log(hashtags);
// ['#NextJS', '#WebDev', '#AI']

Basic Mention Extraction

const comment = 'Great point @rahul_dev! Loop in @priya.codes too.';
const mentions = comment.match(/@[\w.]+/g);
console.log(mentions);
// ['@rahul_dev', '@priya.codes']

Note the mention pattern includes a dot in the character class since many platforms allow dots in usernames (Instagram-style). Adjust the allowed characters to match your own username rules.

Using matchAll for More Detail

match() with the global flag only returns matched strings. If you need the position of each match (for highlighting in a UI, for example), use matchAll(), which returns an iterator of full match objects:

const text = 'Shoutout to @devbrains for the #regex tips!';
const matches = [...text.matchAll(/([@#])(\w+)/g)];

matches.forEach((m) => {
  console.log({
    full: m[0],        // '@devbrains' or '#regex'
    type: m[1],         // '@' or '#'
    value: m[2],         // 'devbrains' or 'regex'
    index: m.index,      // character position in the string
  });
});

Unicode-Friendly Hashtags

\w only covers ASCII letters, digits, and underscore. If your users post in Hindi, Tamil, or other non-Latin scripts, hashtags like #नमस्ते will not match. Use Unicode property escapes with the u flag instead:

const unicodeHashtag = /#[\p{L}\p{N}_]+/gu;

const text = 'खुश रहो #नमस्ते और #India साथ मिलकर!';
console.log(text.match(unicodeHashtag));
// ['#नमस्ते', '#India']

\p{L} matches any Unicode letter and \p{N} matches any Unicode number — together with the u flag, this makes your pattern work across scripts instead of only ASCII.

Common Pitfalls

  • Forgetting the global flag (g) — without it, match() only returns the first hit
  • Matching email addresses accidentally — user@example.com contains an @ that a loose mention regex may partially match; add a word-boundary or space-based lookbehind if this matters for your data
  • Not deduplicating — the same hashtag can appear multiple times in one post; use a Set if you need unique tags
  • Case sensitivity — #NextJS and #nextjs are the same tag conceptually; normalize with .toLowerCase() before storing or counting
function extractUniqueHashtags(text) {
  const matches = text.match(/#[\w]+/g) || [];
  return [...new Set(matches.map((tag) => tag.toLowerCase()))];
}

Frequently Asked Questions

What is the regex to extract hashtags from text?

The pattern /#[\w]+/g matches hashtags made of word characters. For Unicode hashtags that include accented letters or non-Latin scripts, use /#[\p{L}\p{N}_]+/gu with the unicode flag.

What is the regex to extract @mentions from text?

The pattern /@[\w.]+/g matches @ followed by letters, digits, underscores, or dots, which covers most platforms' mention/username formats.

What is the difference between String.match and String.matchAll in JavaScript?

With the global flag, match() returns a simple array of matched strings only. matchAll() returns an iterator of full match objects, including capture groups and index positions, which is useful when you need more detail than just the matched text.

Try the Free AI Regex Generator

Describe any validation rule in plain English and get a working regex instantly — no signup required.

Related articles