From 6220c0b374bc163d37961b17922ba2ee9bd78291 Mon Sep 17 00:00:00 2001 From: 7000pctAUTO Date: Mon, 2 Feb 2026 18:27:17 +0000 Subject: [PATCH] Initial upload with CI/CD workflow --- src/utils.py | 112 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 112 insertions(+) create mode 100644 src/utils.py diff --git a/src/utils.py b/src/utils.py new file mode 100644 index 0000000..44a0014 --- /dev/null +++ b/src/utils.py @@ -0,0 +1,112 @@ +"""Utility functions for Code Pattern Search CLI.""" + +import re +from typing import Optional + + +def validate_regex_pattern(pattern: str) -> tuple[bool, Optional[str]]: + """Validate a regex pattern. + + Returns: + tuple: (is_valid, error_message) + """ + try: + re.compile(pattern) + return True, None + except re.error as e: + return False, str(e) + + +def sanitize_search_query(query: str) -> str: + """Sanitize a search query for safe usage.""" + return re.sub(r'[^\w\s\-_]', '', query).strip() + + +def format_number(num: int) -> str: + """Format a number with appropriate suffixes.""" + if num >= 1_000_000: + return f"{num / 1_000_000:.1f}M" + elif num >= 1_000: + return f"{num / 1_000:.1f}K" + else: + return str(num) + + +def format_duration(seconds: float) -> str: + """Format a duration in human-readable format.""" + if seconds < 60: + return f"{seconds:.1f}s" + elif seconds < 3600: + return f"{seconds / 60:.1f}m" + else: + return f"{seconds / 3600:.1f}h" + + +def get_language_from_extension(extension: str) -> Optional[str]: + """Get programming language from file extension.""" + extension_map = { + ".py": "Python", + ".js": "JavaScript", + ".ts": "TypeScript", + ".jsx": "JavaScript React", + ".tsx": "TypeScript React", + ".java": "Java", + ".go": "Go", + ".rs": "Rust", + ".cpp": "C++", + ".c": "C", + ".cs": "C#", + ".rb": "Ruby", + ".php": "PHP", + ".swift": "Swift", + ".kt": "Kotlin", + ".scala": "Scala", + ".html": "HTML", + ".css": "CSS", + ".json": "JSON", + ".yaml": "YAML", + ".yml": "YAML", + ".md": "Markdown", + ".sh": "Shell", + ".xml": "XML", + ".vue": "Vue", + ".svelte": "Svelte", + } + return extension_map.get(extension.lower()) + + +def truncate_text(text: str, max_length: int = 100, suffix: str = "...") -> str: + """Truncate text to a maximum length.""" + if len(text) <= max_length: + return text + return text[:max_length - len(suffix)] + suffix + + +def calculate_similarity(str1: str, str2: str) -> float: + """Calculate string similarity using Levenshtein distance.""" + if str1 == str2: + return 1.0 + + len1, len2 = len(str1), len(str2) + + if len1 == 0 or len2 == 0: + return 0.0 + + matrix = [[0] * (len2 + 1) for _ in range(len1 + 1)] + + for i in range(len1 + 1): + matrix[i][0] = i + for j in range(len2 + 1): + matrix[0][j] = j + + for i in range(1, len1 + 1): + for j in range(1, len2 + 1): + cost = 0 if str1[i - 1] == str2[j - 1] else 1 + matrix[i][j] = min( + matrix[i - 1][j] + 1, + matrix[i][j - 1] + 1, + matrix[i - 1][j - 1] + cost, + ) + + max_len = max(len1, len2) + return 1.0 - matrix[len1][len2] / max_len