84 lines
2.5 KiB
Python
84 lines
2.5 KiB
Python
import re
|
|
import pandas as pd
|
|
|
|
|
|
def normalize(col_name):
|
|
"""Normalize nama kolom - lowercase, collapse spaces, and strip whitespace"""
|
|
if pd.isna(col_name):
|
|
return ""
|
|
# Collapse multiple whitespace characters into single space
|
|
cleaned = re.sub(r'\s+', ' ', str(col_name))
|
|
return cleaned.strip().lower()
|
|
|
|
|
|
def find_column(source_cols, possible_names):
|
|
"""
|
|
Cari kolom dari beberapa kemungkinan nama.
|
|
|
|
Args:
|
|
source_cols: list kolom dari DataFrame
|
|
possible_names: list kemungkinan nama kolom
|
|
|
|
Returns:
|
|
Nama kolom yang ditemukan, atau None
|
|
"""
|
|
source_cols_map = {normalize(c): c for c in source_cols}
|
|
|
|
# Step 1: Direct normalized match
|
|
for name in possible_names:
|
|
norm_name = normalize(name)
|
|
if norm_name in source_cols_map:
|
|
return source_cols_map[norm_name]
|
|
|
|
# Step 2: Code token match (e.g. 'f1761', 'f5a1', 'f1101', 'f502', etc.)
|
|
for name in possible_names:
|
|
norm_name = normalize(name)
|
|
# Extract question code if present (e.g., 'f1761', 'f5a1', 'f8', etc.)
|
|
match = re.search(r'\b(f\d+[a-z]?\d*)\b', norm_name)
|
|
if match:
|
|
code = match.group(1)
|
|
for orig_norm, orig_col in source_cols_map.items():
|
|
if re.search(r'\b' + re.escape(code) + r'\b', orig_norm):
|
|
return orig_col
|
|
|
|
return None
|
|
|
|
|
|
def get_value(row, source_cols, possible_names, default=None):
|
|
"""
|
|
Ambil nilai dari row dengan cari kolom dulu.
|
|
|
|
Args:
|
|
row: pandas Series (satu row)
|
|
source_cols: list kolom dari DataFrame
|
|
possible_names: list kemungkinan nama kolom
|
|
default: nilai default jika tidak ditemukan
|
|
|
|
Returns:
|
|
Nilai dari row, atau default
|
|
"""
|
|
col = find_column(source_cols, possible_names)
|
|
if col and pd.notna(row.get(col)):
|
|
val = row[col]
|
|
# Convert int/float
|
|
if isinstance(val, (int, float)):
|
|
return int(val) if val == int(val) else val
|
|
return str(val).strip()
|
|
return default
|
|
|
|
|
|
def check_available_columns(df_cols: list) -> dict:
|
|
"""
|
|
Check kolom apa saja yang tersedia di dataframe.
|
|
Berguna untuk debugging.
|
|
"""
|
|
result = {
|
|
'total': len(df_cols),
|
|
'has_email': any('email' in str(c).lower() for c in df_cols),
|
|
'has_nim': any('nim' in str(c).lower() for c in df_cols),
|
|
'has_f1102': 'F1102' in df_cols,
|
|
'has_f5b': 'F5b' in df_cols,
|
|
'has_f1762': 'F1762' in df_cols,
|
|
}
|
|
return result
|