diff --git a/02_conversion_hwp_to_xml.py b/02_conversion_hwp_to_xml.py index f0262c1..ccc4c22 100644 --- a/02_conversion_hwp_to_xml.py +++ b/02_conversion_hwp_to_xml.py @@ -68,7 +68,7 @@ def convert_hwp_to_xml(input_folder, output_folder): input_path = Path(input_folder) # for hwp_file in input_path.glob("DIW_2503B.hwpx"): - for hwp_file in chain(input_path.glob("*.hwp"), input_path.glob("*.hwpx")): + for hwp_file in chain(input_path.glob("DIW-006787-권연호.hwp"), input_path.glob("*.hwpx")): try: # 파일 열기 if hwp_file.suffix == ".hwpx": @@ -174,10 +174,10 @@ if __name__ == "__main__": for exam_round in exam_rounds: folders = [ (f"D:\\project\\HWP\\HWP-Scoring\\input\\{exam_round}\\A\\DIW",f"D:\\project\\HWP\\HWP-Scoring\\output\\{exam_round}\\A\\DIW"), - (f"D:\\project\\HWP\\HWP-Scoring\\input\\{exam_round}\\B\\DIW",f"D:\\project\\HWP\\HWP-Scoring\\output\\{exam_round}\\B\\DIW"), - (f"D:\\project\\HWP\\HWP-Scoring\\input\\{exam_round}\\C\\DIW",f"D:\\project\\HWP\\HWP-Scoring\\output\\{exam_round}\\C\\DIW"), - (f"D:\\project\\HWP\\HWP-Scoring\\input\\{exam_round}\\D\\DIW",f"D:\\project\\HWP\\HWP-Scoring\\output\\{exam_round}\\D\\DIW"), - (f"D:\\project\\HWP\\HWP-Scoring\\input\\{exam_round}\\E\\DIW",f"D:\\project\\HWP\\HWP-Scoring\\output\\{exam_round}\\E\\DIW"), + # (f"D:\\project\\HWP\\HWP-Scoring\\input\\{exam_round}\\B\\DIW",f"D:\\project\\HWP\\HWP-Scoring\\output\\{exam_round}\\B\\DIW"), + # (f"D:\\project\\HWP\\HWP-Scoring\\input\\{exam_round}\\C\\DIW",f"D:\\project\\HWP\\HWP-Scoring\\output\\{exam_round}\\C\\DIW"), + # (f"D:\\project\\HWP\\HWP-Scoring\\input\\{exam_round}\\D\\DIW",f"D:\\project\\HWP\\HWP-Scoring\\output\\{exam_round}\\D\\DIW"), + # (f"D:\\project\\HWP\\HWP-Scoring\\input\\{exam_round}\\E\\DIW",f"D:\\project\\HWP\\HWP-Scoring\\output\\{exam_round}\\E\\DIW"), # (f"D:\\project\\HWP\\HWP-Scoring\\input\\{exam_round}",f"D:\\project\\HWP\\HWP-Scoring\\output\\{exam_round}"), ] diff --git a/JSON/2622/DIW_2622B.json b/JSON/2622/DIW_2622B.json index e544759..cdf875a 100644 --- a/JSON/2622/DIW_2622B.json +++ b/JSON/2622/DIW_2622B.json @@ -778,7 +778,7 @@ "desc": "option값 - 기울임(Italic):i / 굵게(Bold):b" }, "53": { - "chart_xpath": "//c:catAx/c:txPr//a:ea/@typeface", + "chart_xpath": "//c:catAx/c:txPr//a:ea/@typeface | //c:catAx/c:txPr//a:latin/@typeface", "value": "바탕", "points": 1, "category": "ChartOneAnswer", @@ -801,7 +801,7 @@ "desc": "option값 - 기울임(Italic):i / 굵게(Bold):b" }, "56": { - "chart_xpath": "//c:valAx/c:txPr//a:ea/@typeface", + "chart_xpath": "//c:valAx/c:txPr//a:ea/@typeface | //c:valAx/c:txPr//a:latin/@typeface", "value": "바탕", "points": 1, "category": "ChartOneAnswer", @@ -824,7 +824,7 @@ "desc": "option값 - 기울임(Italic):i / 굵게(Bold):b" }, "59": { - "chart_xpath": "//c:legend//a:ea/@typeface", + "chart_xpath": "//c:legend//a:ea/@typeface | //c:legend//a:latin/@typeface", "value": "바탕", "points": 1, "category": "OneAnswer", diff --git a/_copy_files_old.py b/_copy_files_old.py deleted file mode 100644 index 7d30733..0000000 --- a/_copy_files_old.py +++ /dev/null @@ -1,52 +0,0 @@ -import os -import shutil -import unicodedata - -def copy_dic_subdirs(source_root, target_root_a, target_root_b, target_root_c, target_root_d, target_root_e): - for root, dirs, files in os.walk(source_root): - for dir_name in dirs: - if dir_name.lower() == 'diw': # DIW 디렉토리 탐색 - parent_dir = os.path.basename(os.path.dirname(os.path.join(root, dir_name))) - target_root = None - parent_dir = unicodedata.normalize('NFC', parent_dir) - - # 부모 디렉토리가 '2교시'인지, '3교시'인지 확인 - if parent_dir == '1교시': - target_root = target_root_a - elif parent_dir == '2교시': - target_root = target_root_b - elif parent_dir == '3교시': - target_root = target_root_c - elif parent_dir == '4교시': - target_root = target_root_d - elif parent_dir == '5교시': - target_root = target_root_e - - if target_root: - source_dic_path = os.path.join(root, dir_name) - target_dir_name = dir_name.upper() - target_dic_path = os.path.join(target_root, target_dir_name) - - # DIC 하위 디렉토리와 파일 복사 - shutil.copytree(source_dic_path, target_dic_path, dirs_exist_ok=True) - print(f"Copied {source_dic_path} to {target_dic_path}") - - test_folder_path = os.path.join(target_root, "TEST") - os.makedirs(test_folder_path, exist_ok=True) - - - else: - print(f"Skipping {dir_name} under {parent_dir}, as it doesn't match '2교시' or '3교시'.") - -# 사용법 -# exam_round = "2504_2" -exam_round = "2509" -source_directory = r"D:\project\HWP\HWP-Scoring\회차별채점자료\2509" - -target_directory_a = f".\\input\\{exam_round}\\A" # '1교시'의 타겟 경로 -target_directory_b = f".\\input\\{exam_round}\\B" # '2교시'의 타겟 경로 -target_directory_c = f".\\input\\{exam_round}\\C" # '3교시'의 타겟 경로 -target_directory_d = f".\\input\\{exam_round}\\D" # '4교시'의 타겟 경로 -target_directory_e = f".\\input\\{exam_round}\\E" # '5교시'의 타겟 경로 - -copy_dic_subdirs(source_directory, target_directory_a, target_directory_b, target_directory_c, target_directory_d, target_directory_e) diff --git a/base64Decoder.py b/base64Decoder.py deleted file mode 100644 index f214fe8..0000000 --- a/base64Decoder.py +++ /dev/null @@ -1,43 +0,0 @@ -import base64 -import re -from lxml import etree as ET - -xml_path = r"C:\Users\dra\project\HWP-Scoring\output\워드(한글)-009866-성유나.hml" -tree = ET.parse(xml_path) -root = tree.getroot() -# xpath로 바이너리 부분추출 -binary_data = root.xpath('//BINDATA[@Id=//BINITEM[@Format="OLE"]/@BinData]/text()') -binary_data = binary_data[0].encode('utf-8') -# 파일을 읽어들입니다. -# with open('./chartBinData2', 'rb') as file: -# encoded_data = file.read() -# encoded_data 내에 존재하는 ... 태그를 찾아서 삭제 -# 태그는 base64 디코딩을 수행할 때 오류가 발생하므로 삭제합니다. - -# 태그와 그 내부 내용을 삭제합니다. -encoded_data = re.sub(b'', b'', binary_data) -# encoded_data = re.sub(b'', b'', encoded_data) -# print(encoded_data) -encoded_data = encoded_data.replace(b'', b'') -encoded_data = encoded_data.replace(b'\r\n', b'') -# print(encoded_data+b'==') - -# base64 디코딩을 수행합니다. - -decoded_data = base64.b64decode(encoded_data+b'==') - -print(decoded_data) - -# 디코딩된 데이터 내용 중 xml 형식만 추출할 때 , 사이의 데이터만 추출. -start = decoded_data.find(b'') -print(end) -xml_data = decoded_data[start:end+len(b'')] - -# 디코딩된 데이터를 파일로 저장합니다. -with open('ext_BinData.xml', 'wb') as file: - file.write(xml_data) - - -print("Decoding complete. Decoded data saved to 'decoded_chartBinData'.") \ No newline at end of file diff --git a/diff.xlsx b/diff.xlsx deleted file mode 100644 index 4351b79..0000000 Binary files a/diff.xlsx and /dev/null differ diff --git a/diwScoring2.py b/diwScoring2.py index 6aecb84..72c8938 100644 --- a/diwScoring2.py +++ b/diwScoring2.py @@ -532,6 +532,7 @@ class XMLScorer: # 가로 차트일 경우에만 x축과 y축을 바꿔줌 # 세로, 꺾은선, 원형 차트의 경우 그대로 사용 + if "가로" in chart_type: if "catAx" in chart_xpath: chart_xpath = chart_xpath.replace("catAx", "valAx") @@ -543,11 +544,14 @@ class XMLScorer: # valAx의 axPos(축의위치) 속성값으로 축의 방향을 구분함 elif "분산형" in chart_type: if "catAx" in chart_xpath: - # valAx[c:axPos/@val='b'] : 값축의 위치가 bottom (가로,x축) - chart_xpath = chart_xpath.replace("catAx", "valAx[c:axPos/@val='b']") + # 분산형 차트는 catAx 대신 valAx를 사용하거나, + # catAx를 사용하더라도 bottom 위치의 축만 해당 + xpath_with_valax = chart_xpath.replace("catAx", "valAx[c:axPos/@val='b']") + xpath_with_catax = chart_xpath.replace("catAx", "catAx[c:axPos/@val='b']") + # 두 경로를 OR 조건으로 결합 + chart_xpath = xpath_with_valax + " | " + xpath_with_catax elif "valAx" in chart_xpath: - # valAx[c:axPos/@val='l'] : 값축의 위치가 left (세로,y축) - chart_xpath = chart_xpath.replace("valAx", "valAx[c:axPos/@val='l']") + chart_xpath = chart_xpath.replace("valAx", "valAx[c:axPos/@val='l']") chart_items = chart_tree.xpath(chart_xpath, namespaces=namespaces) if chart_xpath else [] @@ -1481,9 +1485,9 @@ def main(): # 채점하고자 하는 유형은 주석 해제 exam_types = [ # 'A', - # 'B', + 'B', # 'C', - 'D', + # 'D', ] test_mode = False diff --git a/hwp_conversion.log b/hwp_conversion.log index 272be03..dcc21dd 100644 --- a/hwp_conversion.log +++ b/hwp_conversion.log @@ -31480,3 +31480,20 @@ 2026-02-13 16:17:57,932 - INFO - 폴더 변환 완료: D:\project\HWP\HWP-Scoring\input\2622\D\DIW -> D:\project\HWP\HWP-Scoring\output\2622\D\DIW 2026-02-13 16:17:58,432 - INFO - 폴더 변환 시작: D:\project\HWP\HWP-Scoring\input\2622\E\DIW -> D:\project\HWP\HWP-Scoring\output\2622\E\DIW 2026-02-13 16:17:59,956 - INFO - 폴더 변환 완료: D:\project\HWP\HWP-Scoring\input\2622\E\DIW -> D:\project\HWP\HWP-Scoring\output\2622\E\DIW +2026-02-20 16:10:59,908 - INFO - 폴더 변환 시작: D:\project\HWP\HWP-Scoring\input\2622\A\DIW -> D:\project\HWP\HWP-Scoring\output\2622\A\DIW +2026-02-20 16:11:16,272 - INFO - 변환 성공: DIW-006787-권연호.hwp -> DIW-006787-권연호.hml +2026-02-20 16:11:16,927 - INFO - 변환 성공: DIW_2622A.hwpx -> DIW_2622A.hml +2026-02-20 16:11:17,276 - INFO - 폴더 변환 완료: D:\project\HWP\HWP-Scoring\input\2622\A\DIW -> D:\project\HWP\HWP-Scoring\output\2622\A\DIW +2026-02-20 16:11:36,896 - INFO - 폴더 변환 시작: D:\project\HWP\HWP-Scoring\input\2622\A\DIW -> D:\project\HWP\HWP-Scoring\output\2622\A\DIW +2026-02-20 16:11:40,978 - INFO - 변환 성공: DIW-006787-권연호.hwp -> DIW-006787-권연호.hml +2026-02-20 16:11:41,661 - INFO - 변환 성공: DIW_2622A.hwpx -> DIW_2622A.hml +2026-02-20 16:11:41,986 - INFO - 폴더 변환 완료: D:\project\HWP\HWP-Scoring\input\2622\A\DIW -> D:\project\HWP\HWP-Scoring\output\2622\A\DIW +2026-02-20 16:11:51,894 - INFO - 폴더 변환 시작: D:\project\HWP\HWP-Scoring\input\2622\A\DIW -> D:\project\HWP\HWP-Scoring\output\2622\A\DIW +2026-02-20 16:12:04,577 - INFO - 변환 성공: DIW-006787-권연호.hwp -> DIW-006787-권연호.hml +2026-02-20 16:12:05,287 - INFO - 변환 성공: DIW_2622A.hwpx -> DIW_2622A.hml +2026-02-20 16:12:05,613 - INFO - 폴더 변환 완료: D:\project\HWP\HWP-Scoring\input\2622\A\DIW -> D:\project\HWP\HWP-Scoring\output\2622\A\DIW +2026-02-20 16:12:07,999 - INFO - 폴더 변환 시작: D:\project\HWP\HWP-Scoring\input\2622\A\DIW -> D:\project\HWP\HWP-Scoring\output\2622\A\DIW +2026-02-20 16:12:37,153 - INFO - 변환 성공: DIW-006787-권연호.hwp -> DIW-006787-권연호.hml +2026-02-20 16:12:37,748 - INFO - 변환 성공: DIW_2622A.hwpx -> DIW_2622A.hml +2026-02-20 16:12:38,053 - INFO - 폴더 변환 완료: D:\project\HWP\HWP-Scoring\input\2622\A\DIW -> D:\project\HWP\HWP-Scoring\output\2622\A\DIW +2026-02-20 16:13:37,659 - INFO - 폴더 변환 시작: D:\project\HWP\HWP-Scoring\input\2622\A\DIW -> D:\project\HWP\HWP-Scoring\output\2622\A\DIW diff --git a/score_result/260213_DIW_2622D_채점결과.xlsx b/score_result/260213_DIW_2622D_채점결과.xlsx index 7e95d1a..6e39b35 100644 Binary files a/score_result/260213_DIW_2622D_채점결과.xlsx and b/score_result/260213_DIW_2622D_채점결과.xlsx differ diff --git a/score_result/260220_DIW_2622B_TEST.xlsx b/score_result/260220_DIW_2622B_TEST.xlsx new file mode 100644 index 0000000..1180395 Binary files /dev/null and b/score_result/260220_DIW_2622B_TEST.xlsx differ diff --git a/score_result/260220_DIW_2622B_채점결과.xlsx b/score_result/260220_DIW_2622B_채점결과.xlsx new file mode 100644 index 0000000..0286fbb Binary files /dev/null and b/score_result/260220_DIW_2622B_채점결과.xlsx differ diff --git a/spellCheck.py b/spellCheck.py deleted file mode 100644 index 255fa20..0000000 --- a/spellCheck.py +++ /dev/null @@ -1,63 +0,0 @@ -from hanspell import spell_checker -from lxml import etree as ET -import difflib - - -# sent = ['서울시 용일동 보건소에서 주최하는 ','즐거운 컬러푸드 영양교실', '은 제8회째 진행하는 행사입니다. 조화로운 식생활과 건강한 삶을 유지하도록 음식 재료의 빛깔만큼이나 다양한 효능이 그 속에 담겨져 있는 컬러푸드에 대한 올바른 영양지식을 제공하고 지역주민들이 직접 참여하여 각각의 맛과 특징을 살펴보고 골고루 먹기의 중요성을 컬러푸드 체험을 통하여 배울 수 있습니다. 이 밖에 아이들을 위한 영양 식단과 고혈압, 당뇨, 비만예방 식단 및 컬러푸드를 이용한 영양 간식 만들기 등 다양한 프로그램이 준비되어 있습니다. 아이들에게는 좋은 경험이 될 수 있는 이번 행사에 많은 참여 부탁드립니다.'] -# spelled_check=spell_checker.check(sent) -xml_path_origin = r"/Users/waterdrw/Works/KAIT/HWP-Scoring/output/정답.hml" -xml_path = r"/Users/waterdrw/Works/KAIT/HWP-Scoring/output/워드(한글)-010036-구준호.hml" -tree = ET.parse(xml_path) -root = tree.getroot() -tree_origin = ET.parse(xml_path_origin) -root_origin = tree_origin.getroot() - -# xpath로 바이너리 부분추출 -input_text = root.xpath('//CHAR/text()') -input_text_origin = root_origin.xpath('//CHAR/text()') - -# 각 요소에서 공백 제거 -input_text = [text.replace(' ', '') for text in input_text] -input_text_origin = [text.replace(' ', '') for text in input_text_origin] - - -# 리스트를 하나의 문자열로 변경 -input_text_str = ''.join(input_text) -input_text_origin_str = ''.join(input_text_origin) - -print("input_text as string:") -print(input_text_str) -print("\ninput_text_origin as string:") -print(input_text_origin_str) - - -# 문자열의 차이를 비교 -diff = difflib.ndiff(input_text_origin_str, input_text_str) -diff_list = list(diff) - -# 차이점을 정리하여 result_diff에 저장 -result_diff = [] -skip_next = False - -for i, line in enumerate(diff_list): - if skip_next: - skip_next = False - continue - # diff_list의 line 시작이 '-'이면서 다음 line이 '+'이면 두 line을 붙여서 맞춤법이 틀린 단어로 판단 - if line.startswith('- '): - if i + 1 < len(diff_list) and diff_list[i + 1].startswith('+ '): - line = line.replace('- ', '-') - next = diff_list[i + 1].replace('+ ', '') - result_diff.append(line+'=>'+next) - skip_next = True - else: - line = line.replace('- ', '-') - result_diff.append(line) - elif line.startswith('+ '): - line = line.replace('+ ', '+') - result_diff.append(line) - -# result_diff 출력 -print("\nResult Differences:") -for diff in result_diff: - print(diff) \ No newline at end of file diff --git a/tg_image_3154048534.tiff b/tg_image_3154048534.tiff deleted file mode 100644 index 468b9b8..0000000 Binary files a/tg_image_3154048534.tiff and /dev/null differ diff --git a/xpathSearch.py b/xpathSearch.py deleted file mode 100644 index 3834247..0000000 --- a/xpathSearch.py +++ /dev/null @@ -1,148 +0,0 @@ -from lxml import etree -from difflib import SequenceMatcher -import json - -class XMLPathHandler: - def __init__(self, xml_file_path): - """ - XML 파일을 로드하고 처리하는 핸들러 - :param xml_file_path: XML 파일 경로 - """ - self.tree = etree.parse(xml_file_path) - self.root = self.tree.getroot() - - def similar(self, a, b): - """ - 두 문자열의 유사도를 계산 - :return: 유사도 점수 (0~1) - """ - return SequenceMatcher(None, a, b).ratio() - - def find_similar_text(self, search_value, element_name, arg_name, threshold=0.8): - """ - XML에서 유사한 텍스트를 찾음 - :param search_value: 찾고자 하는 텍스트 - :param element_name: 검색할 요소 이름 - :param arg_name: 검색할 속성 이름 - :param threshold: 유사도 임계값 - :return: 가장 유사한 텍스트와 점수 - """ - # 특정 요소의 특정 속성을 가진 모든 요소 검색 - xpath = f"//{element_name}[@{arg_name}]" - elements = self.root.xpath(xpath) - best_match = None - best_score = 0 - - for element in elements: - attr_value = element.get(arg_name) - if attr_value is not None: - score = self.similar(search_value, attr_value) - if score > threshold and score > best_score: - best_match = attr_value - best_score = score - - return best_match, best_score - - def build_xpath(self, item): - """ - 설정 항목을 기반으로 XPath 생성 - :param item: 설정 항목 - :return: 구성된 XPath와 매칭된 텍스트, 유사도 점수 - """ - if not all(key in item for key in ['ele', 'arg', 'searchValue']): - return None, None, 0 - - # 유사 텍스트 검색 - matched_text, score = self.find_similar_text( - item['searchValue'], - item['ele'], - item['arg'] - ) - - if matched_text: - # 기본 XPath 템플릿 구성 - xpath = f"//{item['ele']}[@{item['arg']}='{matched_text}']" - - # path가 제공된 경우, 해당 path를 기반으로 XPath 구성 - if 'path' in item and item['path']: - xpath = item['path'].replace(f"[@{item['arg']}='']", f"[@{item['arg']}='{matched_text}']") - xpath = xpath.replace(f"[@{item['arg']}='searchValue']", f"[@{item['arg']}='{matched_text}']") - - return xpath, matched_text, score - - return None, None, 0 - - def process_config(self, config): - """ - 설정된 JSON 설정을 처리 - :param config: JSON 설정 - :return: 처리된 XPath 결과들 - """ - results = {} - - for key, item in config.items(): - results[key] = { - 'original_config': item, - 'processed_results': {} - } - - xpath, matched_text, score = self.build_xpath(item) - - if xpath: - try: - xpath_results = self.root.xpath(xpath) - results[key]['processed_results'] = { - 'original_value': item['searchValue'], - 'matched_value': matched_text, - 'similarity_score': score, - 'xpath': xpath, - 'results': xpath_results - } - except etree.XPathEvalError as e: - results[key]['error'] = f"XPath evaluation error: {str(e)}" - else: - results[key]['error'] = "Unable to build XPath: missing required configuration" - - return results - -# 사용 예시 -def main(): - config = { - "0": { - "path": "//TEXTART[@Text='']/TEXTARTSHAPE/@FontName", - "ele": "TEXTART", - "arg": "Text", - "searchValue": "즐거운컬러푸드영양교실", - "value": "궁서체", - "points": 10 - }, - "1": { - "path": "//PARASHAPE[@Id=//TEXTART[@Text='']/ancestor::P/@ParaShape]/@Align", - "ele": "PARASHAPE", - "arg": "Align", - "searchValue": "Center", - "value": "Center", - "points": 2 - } - } - - xmlPath = r"C:\Users\dra\project\HWP-Scoring\output\1.hml"; - handler = XMLPathHandler(xmlPath) - results = handler.process_config(config) - - # 결과 출력 - for key, result in results.items(): - print(f"\nProcessing config item {key}:") - print(f"Original config: {result['original_config']}") - - if 'error' in result: - print(f"Error: {result['error']}") - else: - processed = result['processed_results'] - print(f"Generated XPath: {processed['xpath']}") - print(f"Matched text: {processed['matched_value']}") - print(f"Similarity score: {processed['similarity_score']}") - print(f"Results found: {processed['results']}") - -if __name__ == "__main__": - main() \ No newline at end of file diff --git a/오류및문제점.md b/오류및문제점.md deleted file mode 100644 index f9f7649..0000000 --- a/오류및문제점.md +++ /dev/null @@ -1,13 +0,0 @@ -# 오류 및 문제점 - -## 1. 원인 파악이나 해결이 어려운 경우 - -### 한글문서(.hwpx)에 수험자가 차트 텍스트 속성을 변경해서 저장했지만 차트 xml파일에 옵션이 적용되지 않는 경우가 있음 - -#### (2-50) 문항 차트 제목 굵게 속성만 - -1. 정상적으로 텍스트 속성이 적용되는 수험자의 차트를 복사 -2. 텍스트 속성이 적용되지 않는 수험자의 한글 파일에 차트를 붙여넣을 경우 -3. 정상적으로 XML파일에 텍스트 속성이 적용 - -- 이로 미루어 볼 때, 차트객체의 문제일 것으로 판단되지만 해결 방안은 현재 없음