Skip to content

How to Extract and Sort Usernames from Text in Python

Learn how to manually parse text to extract valid usernames after @ symbols, filter invalid entries, and sort them by frequency without using regex libraries.

Extracting usernames (mentions) from text is a common task in social media analysis and natural language processing. Typically, a username is defined as a sequence of alphanumeric characters or underscores immediately following an @ symbol.

This guide explains how to parse a string to extract these usernames, filter out invalid entries, and sort them based on their frequency of occurrence without using external libraries like Regex (though Regex is powerful, understanding manual string parsing is a crucial fundamental skill).

The Logic of Extraction

To correctly extract usernames, our algorithm must follow these rules:

  1. Locate: Find the @ symbol.
  2. Validate: Check the characters immediately following it. A valid username character is usually alphanumeric (a-z, 0-9) or an underscore (_).
  3. Stop: Stop capturing characters as soon as an invalid character (like a space, punctuation, or another @) is encountered.
  4. Filter: Ignore empty matches (e.g., a standalone @ or @!).
  5. Sort: Remove duplicates from the final list but order them based on how frequently they appeared in the original text.

Step 1: Finding the Position of Mentions

We can traverse the string using Python's string method .find(). This allows us to jump from one @ to the next efficiently.

text = "Hello @User1 and @User2"
at_index = text.find("@")

while at_index != -1:
    print(f"Found @ at index: {at_index}")
    at_index = text.find("@", at_index + 1)

Output:

Found @ at index: 6
Found @ at index: 17

Step 2: Validating and Extracting Characters

Once an @ is found, we look at the subsequent characters.

text = "@Valid! @Invalid"
at_index = 0 


username = ""
for char in text[at_index + 1:]:
    if char.isalnum() or char == "_":
        username += char
    else:
        break # Stop at the first invalid character (like '!' or space)

print(f"Extracted: {username}")

Output:

Extracted: Valid

Step 3: Sorting by Frequency

The requirement is to return a unique list of usernames, but sorted by how often they appeared in the text (most frequent first).

all_found = ['tutorialreference', 'TutorialReference', 'tutorialreference', 'test']

unique_sorted = sorted(
    list(set(all_found)), 
    key=lambda x: all_found.count(x), 
    reverse=True
)

print(unique_sorted)

Output:

['tutorialreference', 'test', 'TutorialReference']

Complete Code Solution

Here is the robust after_at function that implements the logic: locate, extract, validate, and sort.

def after_at(text):
    """
    Extracts usernames starting with @ from text.
    Valid characters: Alphanumeric and Underscore.
    Returns unique list sorted by frequency (descending).
    """
    usernames = []
    at_index = text.find("@")

    while at_index != -1:
        username = ""
        
        for char in text[at_index + 1 : ]:
            if char.isalnum() or char == "_" or char.isalpha():
                username += char
            else:
                break
        
        if username:
            usernames.append(username)
            
        at_index = text.find("@", at_index + 1)

    result = sorted(
        list(set(usernames)), 
        key=lambda x: usernames.count(x), 
        reverse=True
    )

    return result

if __name__ == "__main__":
    print(f"Test 1: {after_at('@TutorialReference @tutorialreference I won in the @ competition')}")
    print(f"Test 2: {after_at('@!TutorialReference @tutorialreference I won in the competition')}")
    print(f"Test 3: {after_at('I won in the competition@')}")
    print(f"Test 4: {after_at('@!@LabETutorialReferencex @tutorialreference I won in the @TutorialReference competition @experiment')}")

Execution Output:

Test 1: ['tutorialreference', 'TutorialReference']
Test 2: ['tutorialreference']
Test 3: []
Test 4: ['tutorialreference', 'TutorialReference', 'experiment', 'LabETutorialReferencex']

Conclusion

Extracting patterns like usernames manually gives you granular control over what constitutes a "valid" character without relying on complex Regular Expressions.

  1. Iterate using .find() to locate delimiters (@).
  2. Validate strictly using .isalnum() loop logic.
  3. Process the resulting list to filter duplicates and apply custom sorting logic based on frequency.
Navigation