import argparse import os import re import shutil def to_lisp_case(text): # 1. Replace underscores and spaces with dashes text = text.replace("_", "-").replace(" ", "-") # 2. Insert dash between lowercase/number and uppercase (e.g., HeldaneDisplay -> Heldane-Display) text = re.sub(r"([a-z0-9])([A-Z])", r"\1-\2", text) # 3. Insert dash between consecutive capitals and a following word (e.g., VFItalic -> VF-Italic) text = re.sub(r"([A-Z]+)([A-Z][a-z])", r"\1-\2", text) return text.lower() def clean_filename(filename, prefix): # Case-insensitive removal of the prefix from the start of the filename prefix_len = len(prefix) remainder = filename[prefix_len:] remainder = remainder.lstrip("-_") # Handle extensions: Keep only the final extension if "." in remainder: base_part, *extensions = remainder.split(".") final_ext = extensions[-1] else: base_part = remainder final_ext = "" # Remove the trailing random hash (e.g., _SuD3OtC) base_part = re.sub(r"_[a-zA-Z0-9]+$", "", base_part) # Convert the base filename to lisp-case base_part = to_lisp_case(base_part) # Reconstruct the final filename if not base_part: prefix_lisp = to_lisp_case(prefix) return f"{prefix_lisp}.{final_ext}" if final_ext else prefix_lisp return f"{base_part}.{final_ext}" if final_ext else base_part def organize_files(prefix, dry_run=False): # Target directory handles PascalCase -> lisp-case conversion target_dir = to_lisp_case(prefix) prefix_lower = prefix.lower() # Find matching files case-insensitively matching_files = [] for filename in os.listdir("."): if filename.lower().startswith(prefix_lower) and os.path.isfile( filename ): matching_files.append(filename) if not matching_files: print(f"No files found matching prefix: '{prefix}'") return # Create target directory if needed if not os.path.exists(target_dir): if dry_run: print(f"[Dry Run] Would create directory: {target_dir}") else: os.makedirs(target_dir) print(f"Created directory: {target_dir}") # Process files for filename in matching_files: new_name = clean_filename(filename, prefix) old_path = filename new_path = os.path.join(target_dir, new_name) if dry_run: print(f"[Dry Run] Would move: {old_path} -> {new_path}") else: shutil.move(old_path, new_path) print(f"Moved: {old_path} -> {new_path}") if __name__ == "__main__": parser = argparse.ArgumentParser( description="Organize, lowercase, and lisp-case files by prefix." ) parser.add_argument("prefix", help="The prefix to look for") parser.add_argument( "--dry-run", action="store_true", help="Show what actions would be taken without modifying files", ) args = parser.parse_args() organize_files(args.prefix, dry_run=args.dry_run)