Из каждого PDF-файла мне нужно извлечь несколько денежных сумм и затем записать их в файл Excel.
Проблема в том, что в PDF-файле десятичные дроби записываются с надстрочными цифрами после запятой, например:
Код: Выделить всё
310,⁷⁶⁹⁷Код: Выделить всё
−25,³⁴
Я хочу преобразовать их в:
Код: Выделить всё
310.7697Код: Выделить всё
-25.34
- PyMuPDF (), чтобы прочитать текст PDF (и при необходимости вернуться к Tesseract OCR),
Код: Выделить всё
fitz - некоторая очистка регулярных выражений + строк для извлечения сумм,
- openpyxl для записи результатов в Excel.
Текст, который я показываю здесь (
Код: Выделить всё
sample textКод: Выделить всё
import re
def clean_and_convert_amount(amount_str: str) -> float:
"""
Cleans a numeric string like:
- '1 068,²⁷⁵⁶'
- '1 068,2756'
- '−2,2072'
and converts it to a float, preserving:
- the minus sign
- decimal digits, even if they are written as superscript.
"""
if not amount_str:
return 0.0
raw = str(amount_str).strip()
# normalize different minus characters to '-'
raw = raw.replace('−', '-').replace('–', '-')
# if there is any '-' we consider the number negative
is_negative = '-' in raw
# map superscript digits -> normal digits
superscript_map = {
'⁰': '0', 'ⁱ': '1', '¹': '1', '²': '2', '³': '3',
'⁴': '4', '⁵': '5', '⁶': '6', '⁷': '7', '⁸': '8', '⁹': '9',
'\u00B2': '2', # ²
'\u00B3': '3', # ³
'\u00B9': '1', # ¹
}
def normalize_digit(ch: str) -> str:
if ch in superscript_map:
return superscript_map[ch]
if ch.isdigit():
return ch
return ''
# find decimal separator: comma (Romanian) or dot
sep_index = raw.find(',')
if sep_index == -1:
sep_index = raw.find('.')
# no separator -> treat everything as integer
if sep_index == -1:
digits_only = ''.join(normalize_digit(ch) for ch in raw)
if not digits_only:
return 0.0
value = float(digits_only)
return -value if is_negative else value
# split into integer and decimal part
int_raw = raw[:sep_index]
dec_raw = raw[sep_index + 1:]
# integer part: convert superscript/normal digits
integer_digits = ''.join(normalize_digit(ch) for ch in int_raw) or '0'
# decimal part: here we normally have the superscript digits
decimal_digits = ''.join(normalize_digit(ch) for ch in dec_raw) or '0'
number_str = f"{integer_digits}.{decimal_digits}"
try:
value = float(number_str)
except ValueError:
return 0.0
if is_negative:
value = -value
return value
def extract_amounts_from_period(text: str) -> list[float]:
"""
Extract amounts only from sentences of the form:
'din perioada ... în cuantum de '
and ignore sentences containing 'a fost acoperita suma de'
(meaning 'the amount was covered').
"""
if not text:
return []
pattern = re.compile(
r"din\s+perioada\s+([^\n\r]+?)\s*(?:\n|\r\n)?\s*(?:în|in)\s+cuantum\s+de?\s*"
r"([-−–]?\s*[0-9\s,.\u00B2\u00B3\u00B9⁰¹²³⁴⁵⁶⁷⁸⁹]+)",
flags=re.IGNORECASE
)
lower_text = text.lower()
amounts: list[float] = []
for match in pattern.finditer(text):
start = match.start()
amount_str = match.group(2)
# Skip contexts like "a fost acoperita suma de ..."
context_before = lower_text[max(0, start - 150):start]
if "a fost acoperita suma de" in context_before or "a fost acoperită suma de" in context_before:
continue
value = clean_and_convert_amount(amount_str)
amounts.append(value)
return amouts
Код: Выделить всё
amounts = extract_amounts_from_period(text_from_pdf)
total = sum(amounts)
amounts_str = " + ".join(f"{v:.4f}".replace(".", ",") for v in amounts)
total_str = f"{total:.4f}".replace(".", ",")
Проблемы
Десятичные дроби не всегда преобразуются правильно.
Иногда такое значение, как 310,⁷⁶⁹⁷, становится 310,0 или даже 3107697 вместо 310,7697.
Отрицательные суммы иногда теряют знак минус.
Например, -25,³⁴ в PDF-файле может оказаться 25,34 (положительным) в файле Excel.
Ожидаемое поведение
Для примера_текста выше я ожидаю:
Код: Выделить всё
extract_amounts_from_period(sample_text) == [310.7697, -25.34]
310,7697 + -25,3400
Всего ячеек: 285,4297
Каков надежный способ в Python:
Разобрать эти суммы из текста PDF (где десятичные дроби записываются с надстрочными цифрами после запятая) и убедиться, что отрицательный знак всегда сохраняется, чтобы я получал правильные значения с плавающей запятой, такие как 310,7697 и -25,34, прежде чем записывать их в Excel?
Подробнее здесь: https://stackoverflow.com/questions/798 ... like-expon
Мобильная версия