@@ -0,0 +1,141 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Нормализация исходных таблиц NORMY_* → JSON в data/seed/racion/."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
import re
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[1]
|
||||
DEFAULT_SOURCE = ROOT.parents[1] / "для разбора и внедрения /тест/RACION_EXPORT/tables/NORMY"
|
||||
OUT_DIR = ROOT / "data/seed/racion"
|
||||
|
||||
|
||||
def _parse_float_list(raw: str) -> list[float]:
|
||||
"""POPR_K / Normy — элементы разделены «;», десятичная запятая внутри числа."""
|
||||
out: list[float] = []
|
||||
for part in raw.strip().split(";"):
|
||||
p = part.strip()
|
||||
if not p:
|
||||
continue
|
||||
p = p.replace(",", ".")
|
||||
try:
|
||||
out.append(float(p))
|
||||
except ValueError:
|
||||
continue
|
||||
return out
|
||||
|
||||
|
||||
def _read_cp1251(path: Path) -> str:
|
||||
for enc in ("cp1251", "utf-8", "latin-1"):
|
||||
try:
|
||||
return path.read_text(encoding=enc)
|
||||
except UnicodeDecodeError:
|
||||
continue
|
||||
return path.read_text(encoding="latin-1", errors="replace")
|
||||
|
||||
|
||||
def _parse_moskwa_lactir(text: str) -> dict:
|
||||
rows: list[dict] = []
|
||||
udoy_boundaries: list[float] = []
|
||||
for line in text.splitlines():
|
||||
line = line.strip()
|
||||
if not line or line.startswith("=") or "NPITV" in line or "Database:" in line:
|
||||
continue
|
||||
m = re.match(
|
||||
r"^\s*([\d.]+)\s+(\d+)\s+([\d.eE+-]+)\s+(.+)$",
|
||||
line,
|
||||
)
|
||||
if not m:
|
||||
continue
|
||||
npitv = int(float(m.group(1)))
|
||||
pom = int(m.group(2))
|
||||
koef = float(m.group(3))
|
||||
popr_k = _parse_float_list(m.group(4))
|
||||
rows.append({"npitv": npitv, "pom": pom, "koef": koef, "popr_k": popr_k})
|
||||
if npitv == 0 and pom == 2 and koef == 0.0:
|
||||
udoy_boundaries = popr_k
|
||||
return {"udoy_boundaries": udoy_boundaries, "rows": rows}
|
||||
|
||||
|
||||
def _parse_piter_lactir(text: str, *, mass_kg_values: list[float] | None = None) -> dict:
|
||||
entries: list[dict] = []
|
||||
for line in text.splitlines():
|
||||
line = line.strip()
|
||||
if not line or line.startswith("=") or "NPITV" in line or "Database:" in line:
|
||||
continue
|
||||
m = re.match(
|
||||
r"^\s*([\d.]+)\s+([\d.eE+-]+)\s+([\d.eE+-]+)\s+(.+)$",
|
||||
line,
|
||||
)
|
||||
if not m:
|
||||
continue
|
||||
npitv = int(float(m.group(1)))
|
||||
konc = float(m.group(2))
|
||||
udoy = float(m.group(3))
|
||||
normy = _parse_float_list(m.group(4))
|
||||
entries.append({"npitv": npitv, "konc": konc, "udoy": udoy, "normy": normy})
|
||||
masses = mass_kg_values or [400, 450, 500, 550, 600, 650, 700, 750]
|
||||
return {"mass_kg_values": masses, "entries": entries}
|
||||
|
||||
|
||||
def _parse_normy_info(text: str) -> dict:
|
||||
rows: list[dict] = []
|
||||
for line in text.splitlines():
|
||||
line = line.strip()
|
||||
if not line or line.startswith("=") or "NPEREM" in line or "Database:" in line:
|
||||
continue
|
||||
m = re.match(r"^\s*(\d+)\s+(.+)$", line)
|
||||
if not m:
|
||||
continue
|
||||
nperem = int(m.group(1))
|
||||
znachenie = _parse_float_list(m.group(2))
|
||||
rows.append({"nperem": nperem, "znachenie": znachenie})
|
||||
by_nperem = {r["nperem"]: r["znachenie"] for r in rows}
|
||||
mass_kg_values = by_nperem.get(14) or by_nperem.get(13) or [400, 450, 500, 550, 600, 650, 700, 750]
|
||||
return {"rows": rows, "mass_kg_values": mass_kg_values}
|
||||
|
||||
|
||||
def main() -> int:
|
||||
source = Path(sys.argv[1]) if len(sys.argv) > 1 else DEFAULT_SOURCE
|
||||
if not source.is_dir():
|
||||
print(f"Source not found: {source}", file=sys.stderr)
|
||||
return 1
|
||||
OUT_DIR.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
moskwa_path = source / "NORMY_MOSKWA_LACTIR.txt"
|
||||
piter_path = source / "NORMY_PITER_LACTIR.txt"
|
||||
info_path = source / "NORMY_INFO.txt"
|
||||
if not moskwa_path.exists() or not piter_path.exists():
|
||||
print(f"Missing NORMY files in {source}", file=sys.stderr)
|
||||
return 1
|
||||
|
||||
normy_info = _parse_normy_info(_read_cp1251(info_path)) if info_path.exists() else {
|
||||
"rows": [],
|
||||
"mass_kg_values": [400, 450, 500, 550, 600, 650, 700, 750],
|
||||
}
|
||||
moskwa = _parse_moskwa_lactir(_read_cp1251(moskwa_path))
|
||||
piter = _parse_piter_lactir(
|
||||
_read_cp1251(piter_path),
|
||||
mass_kg_values=normy_info.get("mass_kg_values"),
|
||||
)
|
||||
|
||||
(OUT_DIR / "moskwa_lactir.json").write_text(
|
||||
json.dumps(moskwa, ensure_ascii=False, indent=2), encoding="utf-8"
|
||||
)
|
||||
(OUT_DIR / "piter_lactir.json").write_text(
|
||||
json.dumps(piter, ensure_ascii=False, indent=2), encoding="utf-8"
|
||||
)
|
||||
(OUT_DIR / "normy_info.json").write_text(
|
||||
json.dumps(normy_info, ensure_ascii=False, indent=2), encoding="utf-8"
|
||||
)
|
||||
print(f"Wrote {OUT_DIR}/moskwa_lactir.json ({len(moskwa['rows'])} rows)")
|
||||
print(f"Wrote {OUT_DIR}/piter_lactir.json ({len(piter['entries'])} entries)")
|
||||
print(f"Wrote {OUT_DIR}/normy_info.json ({len(normy_info['rows'])} rows)")
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
Reference in New Issue
Block a user