62 lines
1.7 KiB
Python
62 lines
1.7 KiB
Python
from __future__ import annotations
|
||
|
||
import re
|
||
from typing import Optional
|
||
|
||
|
||
def parse_price_fr(text: str | None) -> Optional[float]:
|
||
if not text:
|
||
return None
|
||
# Exemple: "1 249,99 €" -> 1249.99 (gère espaces insécables)
|
||
match = re.search(r"([0-9][0-9\s\.\u00a0\u202f]*(?:[,.][0-9]{2})?)", text)
|
||
if not match:
|
||
return None
|
||
cleaned = match.group(1).replace(" ", "").replace("\u00a0", "").replace("\u202f", "")
|
||
if "," in cleaned:
|
||
cleaned = cleaned.replace(".", "").replace(",", ".")
|
||
elif cleaned.count(".") == 1 and len(cleaned.split(".")[-1]) == 2:
|
||
# conserve le point comme séparateur décimal
|
||
pass
|
||
else:
|
||
cleaned = cleaned.replace(".", "")
|
||
try:
|
||
return float(cleaned)
|
||
except ValueError:
|
||
return None
|
||
|
||
|
||
def parse_rating_value(text: str | None) -> Optional[float]:
|
||
if not text:
|
||
return None
|
||
match = re.search(r"([0-9]+(?:[\.,][0-9]+)?)", text)
|
||
if not match:
|
||
return None
|
||
try:
|
||
return float(match.group(1).replace(",", "."))
|
||
except ValueError:
|
||
return None
|
||
|
||
|
||
def parse_rating_count(text: str | None) -> Optional[int]:
|
||
if not text:
|
||
return None
|
||
digits = re.sub(r"[^0-9]", "", text)
|
||
if not digits:
|
||
return None
|
||
try:
|
||
return int(digits)
|
||
except ValueError:
|
||
return None
|
||
|
||
|
||
def parse_stock_status(text: str | None) -> tuple[Optional[bool], Optional[str]]:
|
||
if not text:
|
||
return None, None
|
||
cleaned = " ".join(text.split())
|
||
lowered = cleaned.lower()
|
||
if "en stock" in lowered or "disponible" in lowered:
|
||
return True, cleaned
|
||
if "indisponible" in lowered or "rupture" in lowered:
|
||
return False, cleaned
|
||
return None, cleaned
|