How to Extract GitHub Usernames from Various URL Formats in Python
The extract_github_username function in github.py normalizes input strings and applies a cascading series of regular expression patterns to capture GitHub handles from HTTPS URLs, bare domains, @-prefixed identifiers, or plain usernames.
The interviewstreet/hiring-agent repository provides a robust implementation for parsing GitHub identifiers from unstructured data. Its extraction engine handles the messy reality of user-submitted URLs by employing defensive normalization and multi-pattern regex matching to reliably isolate the username component.
The Core Extraction Logic
The username extraction implementation resides in github.py at lines 116-138. The extract_github_username function accepts a string parameter github_url and returns an Optional[str] containing the clean handle.
Input Normalization Strategy
Before pattern matching begins, the function sanitizes the input to eliminate common formatting inconsistencies. It removes all space characters using replace(" ", "") and trims leading and trailing whitespace with strip(), ensuring that copy-pasted URLs with accidental spacing do not fail parsing.
The Regex Pattern Pipeline
The function iterates through four distinct regular expression patterns stored in a list, returning the first successful match:
r"https?://github\.com/([^/]+)"– Matches full URLs with HTTP or HTTPS schemes (e.g.,https://github.com/user).r"github\.com/([^/]+)"– Matches bare domain URLs lacking a scheme (e.g.,github.com/user).r"@([^/]+)"– Matches email-style or social-media handles prefixed with@(e.g.,@user).r"^([a-zA-Z0-9-]+)$"– Matches plain usernames containing only alphanumeric characters and hyphens.
Each pattern captures the username in the first regex group. After a match is found, the function checks for query parameters and strips everything from the ? character onward.
def extract_github_username(github_url: str) -> Optional[str]:
if not github_url:
return None
# 1️⃣ Normalise the input
github_url = github_url.replace(" ", "")
github_url = github_url.strip()
# 2️⃣ Patterns for the different ways a username may appear
patterns = [
r"https?://github\.com/([^/]+)", # full URL with scheme
r"github\.com/([^/)+]", # URL without scheme
r"@([^/]+)", # e‑mail‑style handle
r"^([a-zA-Z0-9-]+)$", # plain username
]
# 3️⃣ Scan each pattern until a match is found
for pattern in patterns:
match = re.search(pattern, github_url)
if match:
username = match.group(1)
# Remove any trailing query string (e.g. "?tab=repositories")
if "?" in username:
username = username.split("?", 1)[0]
return username
return None
Supported Input Formats
The extractor handles four distinct input categories frequently encountered in user data:
| Format Type | Example Input | Extracted Result |
|---|---|---|
| Full HTTPS URL | https://github.com/awesome-dev |
awesome-dev |
| Schemeless URL | github.com/awesome-dev |
awesome-dev |
| @-prefixed handle | @awesome-dev |
awesome-dev |
| Plain username | awesome-dev |
awesome-dev |
This tolerant approach ensures that whether a user provides a copied browser URL, a stripped domain, or a simple handle, the system extracts the correct identifier.
Integration with Profile Fetching
According to the interviewstreet/hiring-agent source code, the extraction function serves as a preprocessing step for higher-level operations. The fetch_github_profile function calls extract_github_username to obtain a clean handle before querying the GitHub API for user metadata. Similarly, fetch_all_github_repos relies on this extraction to enumerate repositories after normalizing the input identifier.
The models.py file defines the GitHubProfile dataclass that stores the structured data returned after successful username extraction and API fetching.
Practical Usage Examples
Below are runnable examples demonstrating how the extractor handles various edge cases:
from github import extract_github_username
# Standard HTTPS URL
print(extract_github_username("https://github.com/jane-doe"))
# → jane-doe
# URL without scheme
print(extract_github_username("github.com/jane-doe"))
# → jane-doe
# Username prefixed with @
print(extract_github_username("@jane-doe"))
# → jane-doe
# Plain username (no URL)
print(extract_github_username("jane-doe"))
# → jane-doe
# URL with a query string – the query is stripped away
print(extract_github_username("https://github.com/jane-doe?tab=repositories"))
# → jane-doe
Summary
- The extraction logic lives in
github.pywithin theextract_github_usernamefunction (lines 116-138). - Four regex patterns handle full URLs, schemeless domains, @-prefixed handles, and plain usernames.
- Input normalization removes spaces and trims whitespace before pattern matching.
- Query parameter stripping ensures that trailing arguments like
?tab=repositoriesdo not contaminate the extracted handle. - The function returns
Nonewhen no pattern matches, providing a safe failure mode for downstream API calls.
Frequently Asked Questions
What regex patterns does the system use to identify usernames?
The function uses four patterns in sequence: https?://github\.com/([^/]+) for full URLs, github\.com/([^/]+) for schemeless domains, @([^/]+) for @-prefixed handles, and ^([a-zA-Z0-9-]+)$ for plain alphanumeric usernames with hyphens.
How does the extractor handle whitespace and formatting errors?
The function removes all space characters using replace(" ", "") and trims leading and trailing whitespace with strip() before attempting any regex matching, ensuring that accidental spaces from copy-paste operations do not cause extraction failures.
Which higher-level functions depend on extract_github_username?
According to the source code, fetch_github_profile and fetch_all_github_repos both utilize this extraction function to normalize inputs before querying the GitHub API for profile data or repository listings.
What happens if the input contains a query string?
After a regex match captures the username group, the function checks for the presence of a ? character. If found, it splits the string at the first occurrence and returns only the portion before the query string, effectively discarding parameters like ?tab=repositories or ?ref=master.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →