refactor: big refactor
This commit is contained in:
129
utils.py
129
utils.py
@@ -1,12 +1,82 @@
|
||||
|
||||
# Copyright Stanislav Mironov
|
||||
|
||||
import time
|
||||
import xlrd
|
||||
from coord import Coord, Merged
|
||||
from coord import Coord
|
||||
from translations import ExcelSheetReader
|
||||
import re
|
||||
|
||||
import hashlib
|
||||
|
||||
import requests
|
||||
from urllib.parse import urlsplit, urlunsplit, quote
|
||||
|
||||
def download_file_from_url(url, output_filename):
|
||||
"""
|
||||
Скачивает файл по URL со спецсимволами и пробелами, сохраняя его под указанным именем.
|
||||
|
||||
Args:
|
||||
url (str): Исходный URL, который может содержать пробелы и кириллицу.
|
||||
output_filename (str): Имя файла для сохранения (например, 'calc.xls').
|
||||
"""
|
||||
try:
|
||||
# --- Шаг 1: Правильное кодирование URL ---
|
||||
# Разбираем URL на части: ('https', 'www.vstu.ru', '/path/to file.xls', '', '')
|
||||
parts = urlsplit(url)
|
||||
|
||||
# Кодируем только путь, оставляя слэши '/' безопасными
|
||||
# Это превратит ' ' в '%20', 'В' в '%D0%92' и т.д.
|
||||
encoded_path = quote(parts.path, safe='/-_')
|
||||
|
||||
# Собираем URL обратно из частей с уже закодированным путем
|
||||
encoded_url = urlunsplit((parts.scheme, parts.netloc, encoded_path, parts.query, parts.fragment))
|
||||
|
||||
|
||||
# --- Шаг 2: Скачивание файла ---
|
||||
response = requests.get(encoded_url, stream=True)
|
||||
|
||||
# Проверяем, успешен ли запрос (код 200 OK)
|
||||
# Если сервер вернет ошибку (404, 500 и т.д.), здесь возникнет исключение
|
||||
response.raise_for_status()
|
||||
|
||||
# --- Шаг 3: Сохранение файла ---
|
||||
# Открываем файл для записи в бинарном режиме ('wb')
|
||||
# Использование 'with' гарантирует, что файл будет закрыт автоматически
|
||||
with open(output_filename, 'wb') as f:
|
||||
for chunk in response.iter_content(chunk_size=8192):
|
||||
f.write(chunk)
|
||||
|
||||
print(f"✅ Файл успешно скачан и сохранен как '{output_filename}'")
|
||||
|
||||
except requests.exceptions.RequestException as e:
|
||||
print(f"❌ Ошибка скачивания: {e}")
|
||||
|
||||
except Exception as e:
|
||||
print(f"❌ Произошла непредвиденная ошибка: {e}")
|
||||
|
||||
|
||||
def calculate_sha1(filepath):
|
||||
"""
|
||||
Calculates the SHA1 hash of a given file.
|
||||
|
||||
Args:
|
||||
filepath (str): The path to the file.
|
||||
|
||||
Returns:
|
||||
str: The hexadecimal representation of the SHA1 hash, or None if the file is not found.
|
||||
"""
|
||||
sha1_hash = hashlib.sha1()
|
||||
try:
|
||||
with open(filepath, "rb") as f:
|
||||
# Read the file in chunks to handle large files efficiently
|
||||
for chunk in iter(lambda: f.read(4096), b""):
|
||||
sha1_hash.update(chunk)
|
||||
return sha1_hash.hexdigest()
|
||||
except FileNotFoundError:
|
||||
print(f"Error: File not found at {filepath}")
|
||||
return None
|
||||
except Exception as e:
|
||||
print(f"An error occurred: {e}")
|
||||
return None
|
||||
|
||||
class StepTimeCounter:
|
||||
def __init__(self):
|
||||
@@ -69,58 +139,6 @@ def parse_all_dirt(reader: "ExcelSheetReader", min_pos: Coord, right, down, with
|
||||
|
||||
return RET
|
||||
|
||||
# GEMINI GENERATED
|
||||
def normalize_name(raw_name):
|
||||
"""
|
||||
Приводит разнородные записи ФИО к единому структурированному виду.
|
||||
"""
|
||||
# Шаг 1: Очистка
|
||||
name = re.sub(r'\s+', ' ', raw_name).strip()
|
||||
|
||||
# Шаг 2: Извлечение звания
|
||||
known_titles = ['проф.', 'доц.', 'акад.', 'к.т.н.', 'д.м.н.']
|
||||
title = None
|
||||
for t in known_titles:
|
||||
if name.lower().startswith(t):
|
||||
title = t
|
||||
# Удаляем звание из строки, убираем лишние пробелы
|
||||
name = name[len(t):].strip()
|
||||
break
|
||||
|
||||
# Шаг 3 и 4: Разделение и идентификация
|
||||
parts = name.split(' ')
|
||||
last_name = None
|
||||
initials = None
|
||||
|
||||
# Простой эвристический анализ
|
||||
# Ищем инициалы (содержат точку или состоят из 1-2 заглавных букв)
|
||||
initials_parts = []
|
||||
name_parts = []
|
||||
|
||||
for part in parts:
|
||||
if '.' in part or (1 <= len(part) <= 2 and part.isupper()):
|
||||
initials_parts.append(part)
|
||||
else:
|
||||
# Считаем все остальное частью фамилии (для двойных фамилий)
|
||||
name_parts.append(part)
|
||||
|
||||
if name_parts:
|
||||
last_name = " ".join(name_parts)
|
||||
|
||||
if initials_parts:
|
||||
initials = "".join(initials_parts) # Сливаем "А." и "Н." в "А.Н."
|
||||
|
||||
# Если фамилия не найдена (например, только инициалы),
|
||||
# но есть части, считаем первую часть фамилией
|
||||
if not last_name and name_parts:
|
||||
last_name = name_parts[0]
|
||||
|
||||
return {
|
||||
"last_name": last_name,
|
||||
"initials": initials,
|
||||
"title": title
|
||||
}
|
||||
|
||||
def excel_coordinate(row, col):
|
||||
"""
|
||||
Преобразует координаты строки и столбца (начиная с 0) в эквивалент Excel (например, A7, CB34).
|
||||
@@ -179,5 +197,6 @@ def weekday_to_num(st: str):
|
||||
if st.upper().strip().startswith("ВОСКР"):
|
||||
return 7
|
||||
|
||||
print(f"Unknown weekday num for str: {st}; returnted -1")
|
||||
return -1
|
||||
|
||||
Reference in New Issue
Block a user