Skip to content

Instantly share code, notes, and snippets.

@n3rada
Created February 16, 2024 11:00
Show Gist options
  • Save n3rada/866c22fcefe1d4b64f86cd1bbebe1cbd to your computer and use it in GitHub Desktop.
Save n3rada/866c22fcefe1d4b64f86cd1bbebe1cbd to your computer and use it in GitHub Desktop.
A Python script to generate a wide array of possible usernames from first and last names listed in a file. It supports various combinations including initials, partial names, and common separators
#!/usr/bin/env python3
import sys
from pathlib import Path
import argparse
from itertools import product
from typing import Generator
def username_variants_generator(fname: str, lname: str) -> Generator[str, None, None]:
"""
Generate a comprehensive list of possible usernames based on a person's first and last name.
This generator yields combinations of the first name (fname) and last name (lname),
using various separators and including initials, partial first names, and full names
to produce a wide array of potential usernames.
Args:
fname (str): The first name of the person.
lname (str): The last name of the person.
Yields:
Generator[str, None, None]: A generator yielding strings, each a possible username variant.
"""
separators = ['', '.', '_', '-']
parts = [fname, lname]
initials = [fname[0], lname[0]]
# Full name and initials with separators
for sep in separators:
yield from [sep.join(parts)] # Full name with separator
yield from [sep.join(initials)] # Initials with separator
# Combinations with separators for initials and parts
yield from [sep.join([p1, p2]) for p1, p2 in product(parts + initials, repeat=2) if p1 != p2]
# Partial first name variants with full last name
for i in range(1, len(fname)):
partial_fname = fname[:i]
for sep in separators:
yield f"{partial_fname}{sep}{lname}"
# Additional comprehensive variants including edge cases
# Unique combinations of initials and names without separators
yield fname + lname[0]
yield fname[0] + lname
yield lname + fname[0]
yield lname[0] + fname
# Individual name parts
yield fname
yield lname
# Additional handling for single character first names to include them with lname
if len(fname) == 1:
for sep in separators:
yield f"{fname}{sep}{lname}"
yield f"{lname}{sep}{fname}"
def generate_usernames(file_name: str) -> None:
"""
Reads a file containing first and last names, and prints a list of possible username variants for each name.
This function opens a specified file and reads it line by line. Each line is expected to contain
a person's first name and last name, separated by space. It generates username variants by combining
the first and last names in various ways, including using initials, dots, and underscores. Each variant
is printed to standard output.
Args:
file_name (str): The path to the file containing the names. Each line of the file should
contain one name pair (first name and last name) separated by space.
"""
path = Path(file_name)
if not path.exists():
print(f'File {file_name} not found')
sys.exit(1)
file_content = path.read_text()
for line in file_content.strip().split('\n'):
name = ''.join(c for c in line if c.isalpha() or c == ' ')
if not name:
continue
tokens = name.lower().split()
fname, *middle, lname = tokens if len(tokens) > 1 else (tokens[0], '', '')
lname = ''.join(middle + [lname]) if middle else lname
for variant in username_variants_generator(fname, lname):
print(variant)
if __name__ == '__main__':
parser = argparse.ArgumentParser(description='Generate a list of possible usernames from a person\'s first and last name.')
parser.add_argument('file_name', type=str, help='The file containing names to generate usernames from.')
args = parser.parse_args()
generate_usernames(args.file_name)
@n3rada
Copy link
Author

n3rada commented Feb 16, 2024

If you have in input names.txt:

Bob Farmer
Philippe Katerine

You'll got:

bobfarmer
bf
bobfarmer
bobb
bobf
farmerbob
farmerb
farmerf
bbob
bfarmer
bf
fbob
ffarmer
fb
bob.farmer
b.f
bob.farmer
bob.b
bob.f
farmer.bob
farmer.b
farmer.f
b.bob
b.farmer
b.f
f.bob
f.farmer
f.b
bob_farmer
b_f
bob_farmer
bob_b
bob_f
farmer_bob
farmer_b
farmer_f
b_bob
b_farmer
b_f
f_bob
f_farmer
f_b
bob-farmer
b-f
bob-farmer
bob-b
bob-f
farmer-bob
farmer-b
farmer-f
b-bob
b-farmer
b-f
f-bob
f-farmer
f-b
bfarmer
b.farmer
b_farmer
b-farmer
bofarmer
bo.farmer
bo_farmer
bo-farmer
bobf
bfarmer
farmerb
fbob
bob
farmer
philippekaterine
pk
philippekaterine
philippep
philippek
katerinephilippe
katerinep
katerinek
pphilippe
pkaterine
pk
kphilippe
kkaterine
kp
philippe.katerine
p.k
philippe.katerine
philippe.p
philippe.k
katerine.philippe
katerine.p
katerine.k
p.philippe
p.katerine
p.k
k.philippe
k.katerine
k.p
philippe_katerine
p_k
philippe_katerine
philippe_p
philippe_k
katerine_philippe
katerine_p
katerine_k
p_philippe
p_katerine
p_k
k_philippe
k_katerine
k_p
philippe-katerine
p-k
philippe-katerine
philippe-p
philippe-k
katerine-philippe
katerine-p
katerine-k
p-philippe
p-katerine
p-k
k-philippe
k-katerine
k-p
pkaterine
p.katerine
p_katerine
p-katerine
phkaterine
ph.katerine
ph_katerine
ph-katerine
phikaterine
phi.katerine
phi_katerine
phi-katerine
philkaterine
phil.katerine
phil_katerine
phil-katerine
philikaterine
phili.katerine
phili_katerine
phili-katerine
philipkaterine
philip.katerine
philip_katerine
philip-katerine
philippkaterine
philipp.katerine
philipp_katerine
philipp-katerine
philippek
pkaterine
katerinep
kphilippe
philippe
katerine

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment