151 lines
7.4 KiB
Python
151 lines
7.4 KiB
Python
import glob, re, os, sys, fitz
|
|
|
|
sys.stdout.reconfigure(encoding='utf-8')
|
|
|
|
pdf_path = 'resources/knowledge/original/원가계산/건설공사_표준품셈/2026년_건설공사_표준품셈.pdf'
|
|
doc = fitz.open(pdf_path)
|
|
|
|
target_files = []
|
|
target_files.extend(glob.glob('resources/knowledge/original/원가계산/건설공사_표준품셈/02_토목부문/*.md'))
|
|
target_files.extend(glob.glob('resources/knowledge/original/원가계산/건설공사_표준품셈/05_유지관리부문/*.md'))
|
|
target_files.append('resources/knowledge/original/원가계산/건설공사_표준품셈/04_기계설비부문/제13장_플랜트설비공사.md')
|
|
|
|
print(f"Target files: {len(target_files)}")
|
|
|
|
# Build PDF index of section headings
|
|
print("Indexing PDF pages for section headings...")
|
|
sec_to_pdf_page = {}
|
|
for p_num in range(len(doc)):
|
|
text = doc[p_num].get_text()
|
|
# Find all patterns like X-Y-Z or X-Y
|
|
matches = re.findall(r'(\d+-\d+(?:-\d+)?)', text)
|
|
for m in matches:
|
|
sec_to_pdf_page.setdefault(m, []).append(p_num)
|
|
|
|
print(f"Indexed {len(sec_to_pdf_page)} section numbers in PDF.")
|
|
|
|
# Now parse each markdown file's tables that have a Remarks column
|
|
discrepancies = []
|
|
|
|
for fpath in target_files:
|
|
fname = os.path.basename(fpath)
|
|
with open(fpath, 'r', encoding='utf-8') as f:
|
|
lines = f.readlines()
|
|
|
|
current_sec_num = 'UNKNOWN'
|
|
current_sec_title = 'UNKNOWN'
|
|
in_table = False
|
|
headers = []
|
|
table_rows = []
|
|
start_line = 0
|
|
|
|
for idx, line in enumerate(lines):
|
|
line_s = line.strip()
|
|
sec_m = re.search(r'(\d+-\d+(?:-\d+)?)(\s+[^\n(]+)?', line_s)
|
|
if sec_m and not line_s.startswith('|'):
|
|
current_sec_num = sec_m.group(1).strip()
|
|
current_sec_title = line_s
|
|
|
|
if line_s.startswith('|') and not line_s.startswith('|---'):
|
|
cols = [c.strip() for c in line_s.split('|')[1:-1]]
|
|
if not in_table:
|
|
# check if header has 비고 or 비 고
|
|
if any('비고' in c or '비 고' in c for c in cols):
|
|
headers = cols
|
|
in_table = True
|
|
start_line = idx + 1
|
|
table_rows = []
|
|
continue
|
|
if in_table:
|
|
table_rows.append((idx + 1, cols))
|
|
else:
|
|
if in_table and (line_s == '' or not line_s.startswith('|')):
|
|
# Check this table against PDF!
|
|
remarks_col_idx = -1
|
|
for ci, h in enumerate(headers):
|
|
if '비고' in h or '비 고' in h:
|
|
remarks_col_idx = ci
|
|
break
|
|
|
|
if remarks_col_idx != -1 and len(table_rows) > 0:
|
|
md_remarks = [r[1][remarks_col_idx] if remarks_col_idx < len(r[1]) else '' for r in table_rows]
|
|
|
|
# Find matching page in PDF
|
|
cand_pages = sec_to_pdf_page.get(current_sec_num, [])
|
|
# filter to body pages (> 45)
|
|
body_pages = [p for p in cand_pages if p > 45]
|
|
|
|
found_pdf_table = False
|
|
for p in body_pages:
|
|
page = doc[p]
|
|
tabs = page.find_tables()
|
|
for tab in tabs:
|
|
df = tab.extract()
|
|
if not df or len(df) < 2:
|
|
continue
|
|
pdf_header = [c if c else '' for c in df[0]]
|
|
# Check if pdf_header has 비고
|
|
pdf_rem_idx = -1
|
|
for pci, ph in enumerate(pdf_header):
|
|
if '비고' in ph or '비 고' in ph:
|
|
pdf_rem_idx = pci
|
|
break
|
|
if pdf_rem_idx != -1:
|
|
found_pdf_table = True
|
|
# Extract pdf remarks
|
|
pdf_remarks_raw = [r[pdf_rem_idx] if pdf_rem_idx < len(r) and r[pdf_rem_idx] else '' for r in df[1:]]
|
|
# Flatten any multi-line in pdf remarks
|
|
pdf_remarks_split = []
|
|
for pr in pdf_remarks_raw:
|
|
pdf_remarks_split.extend([sub.strip() for sub in pr.split('\n') if sub.strip()])
|
|
|
|
# Compare count of non-empty remarks or ditto presence
|
|
md_non_empty = [m for m in md_remarks if m]
|
|
pdf_non_empty = [p for p in pdf_remarks_split if p]
|
|
|
|
# Check if ditto marks or numbers mismatch
|
|
has_ditto = any('〃' in m or '"' in m for m in md_remarks) or any('〃' in p for p in pdf_non_empty)
|
|
|
|
# If row count differs significantly or ditto count differs
|
|
md_ditto_cnt = sum(1 for m in md_remarks if '〃' in m or '"' in m)
|
|
pdf_ditto_cnt = sum(1 for p in pdf_non_empty if '〃' in p or '"' in p)
|
|
|
|
if has_ditto and md_ditto_cnt != pdf_ditto_cnt:
|
|
discrepancies.append({
|
|
'file': fname,
|
|
'sec': current_sec_num,
|
|
'line': start_line,
|
|
'type': 'Ditto count mismatch',
|
|
'md_dittos': md_ditto_cnt,
|
|
'pdf_dittos': pdf_ditto_cnt,
|
|
'md_remarks': md_remarks,
|
|
'pdf_remarks': pdf_remarks_raw,
|
|
'page': p + 1
|
|
})
|
|
elif len(md_remarks) != len(df) - 1:
|
|
# Row count mismatch in table with remarks
|
|
discrepancies.append({
|
|
'file': fname,
|
|
'sec': current_sec_num,
|
|
'line': start_line,
|
|
'type': 'Row count mismatch in remarks table',
|
|
'md_rows': len(md_remarks),
|
|
'pdf_rows': len(df) - 1,
|
|
'md_remarks': md_remarks,
|
|
'pdf_remarks': pdf_remarks_raw,
|
|
'page': p + 1
|
|
})
|
|
in_table = False
|
|
headers = []
|
|
table_rows = []
|
|
|
|
print(f"\nTotal Discrepancies found: {len(discrepancies)}")
|
|
for d in discrepancies:
|
|
print(f"\n[{d['file']}] {d['sec']} (L{d['line']}, PDF page {d.get('page')}) -> {d['type']}")
|
|
if 'md_dittos' in d:
|
|
print(f" MD dittos: {d['md_dittos']} vs PDF dittos: {d['pdf_dittos']}")
|
|
if 'md_rows' in d:
|
|
print(f" MD rows: {d['md_rows']} vs PDF rows: {d['pdf_rows']}")
|
|
print(f" MD remarks: {d['md_remarks'][:6]}")
|
|
print(f" PDF remarks: {d['pdf_remarks'][:6]}")
|