C.W.K.
Stream
Lesson 02 of 12 · published

URL Matching

~10 min · url, extraction

Level 0Pattern-Curious
0 XP0/90 lessons0/15 achievements
0/100 XP to next level100 XP to go0% complete

Two questions, two patterns

"Match a URL" is actually two different questions:

  1. Is this whole string a URL? (validation)
  2. Find URLs in this text. (extraction)

Different patterns, different anchoring.

Validation pattern

^https?://[\w-]+(\.[\w-]+)+(/[\w./?%&=+#-]*)?$

Accepts http or https, requires a domain with at least one dot, optionally a path with allowed URL characters.

Extraction pattern

For finding URLs in free-form text, you want to be more permissive but stop at obvious word boundaries:

https?://[^\s)]+

Matches http(s):// followed by anything that's not whitespace or a closing paren. The closing-paren stop prevents URLs in markdown like (https://example.com) from including the trailing ).

The trailing punctuation problem

URLs at the end of sentences pick up trailing periods, commas, parens. Solution: use a negated class that excludes those, OR strip trailing punctuation in code after the match.

Don't try to fully validate URLs with regex

Real URL validation is messy: scheme variants, IP literals, port numbers, internationalized domains, fragment encoding. For "does this URL parse and resolve?", use your language's URL library: Python urllib.parse.urlparse, JavaScript new URL(...), Go net/url.

Code

URL patterns·python
import re

# Validation (whole-string)
URL_VALID = re.compile(r'^https?://[\w-]+(\.[\w-]+)+(/[\w./?%&=+#-]*)?$')

bool(URL_VALID.fullmatch('https://example.com'))                # True
bool(URL_VALID.fullmatch('http://sub.domain.com/path?q=1'))     # True
bool(URL_VALID.fullmatch('not a url'))                          # False
bool(URL_VALID.fullmatch('ftp://example.com'))                  # False (only http(s))

# Extraction (find in text)
URL_FIND = re.compile(r'https?://[^\s)]+')
re.findall(URL_FIND, 'see https://pippa.dev or https://cwk.io for more (https://other.org)')
# ['https://pippa.dev', 'https://cwk.io', 'https://other.org']

# Strip trailing punctuation in post-processing
import string
def clean_url(url):
    return url.rstrip(string.punctuation)

# For real validation — use the URL library
from urllib.parse import urlparse
parsed = urlparse('https://sub.example.com:8080/path?q=1')
print(parsed.scheme)   # 'https'
print(parsed.netloc)   # 'sub.example.com:8080'
print(parsed.path)     # '/path'

External links

Exercise

Find a place in your codebase that detects or extracts URLs. Audit: does it use regex? Does it validate or extract? Should the validation pass through a URL library? Often the answer is yes.

Progress

Progress is local-only — sign in to sync across devices.
Spotted a bug or have feedback on this page?Report an Issue

Comments 0

🔔 Reply notifications (sign in)
Sign inPlease sign in to comment.

No comments yet — be the first.