Match a Markdown link
Match a Markdown link and split it into its display text and URL, handy for auditing docs or building a link checker.
Last updated
Matches
- Check the [docs](https://example.com) for details
- See [our repo](/path/to/repo) here
Doesn’t match
- Just a [bracketed] phrase without a link
- Visit https://example.com directly
Why it’s written this way
The first capture group ([^\]]+) sits inside escaped brackets \[ \] and grabs the link text, everything up to the next closing bracket. The second, ([^)\s]+), sits inside escaped parentheses and grabs the URL, stopping at whitespace or the closing paren.
Splitting the match into two groups lets calling code pull the display text and the destination separately instead of re-parsing the whole matched string.
Edge cases to know
- →A URL containing a literal space, such as an unencoded file path, breaks the match early because [^)\s]+ stops at the first whitespace it meets.
- →It doesn't distinguish a real link from an image embed, which uses a leading ! before the same bracket-paren shape — both match identically here.
- →Nested brackets in the link text, like [a [b] link](url), aren't handled — the character class stops at the first closing bracket it finds.
Part by part
- \[([^\]]+)\]
- The link text in square brackets, captured as group 1. The inner class excludes the closing bracket so the match cannot run past its own label.
- \(([^)\s]+)\)
- The URL in parentheses, captured as group 2. Excluding whitespace as well as the closing bracket stops it swallowing an optional title.
Common mistakes
\[(.*)\]\((.*)\)Greedy dots make two links on one line match as a single one, capturing everything from the first bracket to the last parenthesis — including the text between the links.
\[([^\]]+)\]\(([^)\s]+)\)\[([^\]]+)\]\(([^)]+)\)Allowing whitespace in the URL group pulls in the optional link title, so the captured href becomes the URL plus a quoted string, which then fails when used as a link.
\[([^\]]*)\]\(([^)\s]+)\)A star allows empty link text, which matches the image and footnote syntaxes as well as genuinely broken links. Requiring at least one character keeps the results meaningful.
Questions
Does it match images as well as links?
It matches the bracket-parenthesis part of an image, missing only the leading exclamation mark. Check the character before the match, or prepend a negative lookbehind, if you need to tell them apart.
Does it handle nested brackets in the link text?
No. Text like [see [1] here] terminates at the inner bracket, because the class excludes it. Nesting cannot be expressed in a regular expression at all — this is a genuine limit rather than an oversight.
Does it match reference-style links?
No. Those use a second pair of square brackets pointing at a definition elsewhere in the document, which is a different shape and needs both halves matched and then joined.
Can I use it to rewrite links?
For straightforward documents, yes — the two capture groups give you the text and the URL to rebuild with. Be careful with code blocks, since the pattern has no idea it is inside one and will happily rewrite an example.