# How to Extract GitHub Usernames from Various URL Formats in Python

> Learn how to extract GitHub usernames from various URL formats using Python. This function normalizes input and uses regex to capture handles from URLs, bare domains, or plain usernames.

- Repository: [HackerRank/hiring-agent](https://github.com/interviewstreet/hiring-agent)
- Tags: how-to-guide
- Published: 2026-07-19

---

**The `extract_github_username` function in [`github.py`](https://github.com/interviewstreet/hiring-agent/blob/main/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`](https://github.com/interviewstreet/hiring-agent/blob/main/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.

```python
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`](https://github.com/interviewstreet/hiring-agent/blob/main/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:

```python
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.py`](https://github.com/interviewstreet/hiring-agent/blob/main/github.py)** within the `extract_github_username` function (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=repositories` do not contaminate the extracted handle.
- The function returns **`None`** when 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`.