Created
August 22, 2025 18:24
-
-
Save s3rgeym/4fe5af48f2a76d7503517e023ea19592 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python | |
import argparse | |
import pathlib | |
import re | |
import sys | |
from collections import defaultdict | |
from functools import partial | |
print_err = partial(print, file=sys.stderr) | |
TRANS_TABLE = defaultdict( | |
str, | |
{ | |
"а": "a", | |
"б": "b", | |
"в": "v", | |
"г": "g", | |
"д": "d", | |
"е": "e", | |
"ё": "yo", | |
"ж": "zh", | |
"з": "z", | |
"и": "i", | |
"й": "y", | |
"к": "k", | |
"л": "l", | |
"м": "m", | |
"н": "n", | |
"о": "o", | |
"п": "p", | |
"р": "r", | |
"с": "s", | |
"т": "t", | |
"у": "u", | |
"ф": "f", | |
"х": "h", | |
"ц": "ts", | |
"ч": "ch", | |
"ш": "sh", | |
"щ": "shch", | |
"ъ": "", | |
"ы": "y", | |
"ь": "", | |
"э": "e", | |
"ю": "yu", | |
"я": "ya", | |
"А": "A", | |
"Б": "B", | |
"В": "V", | |
"Г": "G", | |
"Д": "D", | |
"Е": "E", | |
"Ё": "Yo", | |
"Ж": "Zh", | |
"З": "Z", | |
"И": "I", | |
"Й": "Y", | |
"К": "K", | |
"Л": "L", | |
"М": "M", | |
"Н": "N", | |
"О": "O", | |
"П": "P", | |
"Р": "R", | |
"С": "S", | |
"Т": "T", | |
"У": "U", | |
"Ф": "F", | |
"Х": "H", | |
"Ц": "Ts", | |
"Ч": "Ch", | |
"Ш": "Sh", | |
"Щ": "Shch", | |
"Ъ": "", | |
"Ы": "Y", | |
"Ь": "", | |
"Э": "E", | |
"Ю": "Yu", | |
"Я": "Ya", | |
}, | |
) | |
def translit(text): | |
return "".join(TRANS_TABLE.get(char, char) for char in text) | |
def translit_filenames(directory_path: pathlib.Path, to_lower: bool = False) -> None: | |
for item in sorted(directory_path.rglob("*"), reverse=True): | |
if item.name.startswith("."): | |
continue | |
new_name = translit(item.name) | |
new_name = re.sub(r"\s+", "-", new_name).strip("-") | |
if to_lower: | |
new_name = new_name.lower() | |
if item.name != new_name: | |
new_path = item.parent / new_name | |
if new_path.exists() and new_path != item: | |
continue | |
print_err(f"{item} -> {new_path}") | |
item.rename(new_path) | |
if __name__ == "__main__": | |
parser = argparse.ArgumentParser( | |
description="Renames files and directories recursively using transliteration." | |
) | |
parser.add_argument( | |
"directory", type=pathlib.Path, help="Path to the directory to process." | |
) | |
parser.add_argument( | |
"-lc", | |
"--lower-case", | |
"--lower", | |
help="To lower case", | |
action=argparse.BooleanOptionalAction, | |
default=False, | |
) | |
args = parser.parse_args() | |
if args.directory.is_dir(): | |
translit_filenames(args.directory, args.lower_case) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment