v2 - 문제2 45문항

This commit is contained in:
2025-05-15 18:06:06 +09:00
parent 872d5f6da6
commit 20c4359cb8
8 changed files with 197 additions and 66 deletions

View File

@@ -11,6 +11,8 @@ from difflib import SequenceMatcher
import pandas as pd
import base64
import math
from itertools import chain
# from xpathSearch import XMLPathHandler
class XMLScorer:
@@ -202,6 +204,7 @@ class XMLScorer:
points = criterion.get('points', 0)
category = criterion.get('category', None)
item = criterion.get('item', None)
option = criterion.get('option', None)
similar_text = None
# search_value가 있는 경우
@@ -211,7 +214,11 @@ class XMLScorer:
xpath = xpath.replace('{searchValue}', similar_text)
if xpath2 is not None:
xpath2 = xpath2.replace('{searchValue}', similar_text)
if option:
xpath = xpath.replace('{option}', option) if xpath else ""
xpath2 = xpath2.replace('{option}', option) if xpath2 else ""
# 문항 별 채점 결과 저장
scoring = {
'section': section_id,
@@ -224,7 +231,7 @@ class XMLScorer:
'deductions': [] # 각 기준별 감점 내역
}
if "PageSetting" in (category or ""):
if (category or "") == "PageSetting":
items = root.xpath(xpath)
error_range = criterion.get('tolerance', 0)
@@ -244,7 +251,7 @@ class XMLScorer:
if scoring['points'] > 0:
break
elif "BasicSetting" in (category or ""):
elif (category or "") == "BasicSetting":
# 바탕글(기본설정) 요소
normal_style = root.xpath("//STYLE[@Name='바탕글']")
@@ -277,17 +284,18 @@ class XMLScorer:
self.evaluate_answer(scoring, user_answer, right_answer, points, method="equal")
# 오타 감점 부분은 미리 계산 하고, 이후 점수만 계산
elif "오타감점" in (category or ""):
elif (category or "") == "오타감점":
points = self.get_typo_score()
self.total_score += points
self.partial_score += points
scoring['points'] = points
# 정답이 하나인 경우
elif "SingleAnswer" in (category or ""):
elif (category or "") == "OneAnswer":
items = root.xpath(xpath)
items2 = root.xpath(xpath2) if xpath2 else []
for item in items:
for item in chain(items, items2):
user_answer = item
self.evaluate_answer(scoring, user_answer, right_answer, points)
@@ -295,24 +303,21 @@ class XMLScorer:
if scoring['points'] > 0:
break
elif "DoubleAnswer" in (category or ""):
elif (category or "") == "DoubleAnswer":
items1 = root.xpath(xpath)
items2 = root.xpath(xpath2)
items2 = root.xpath(xpath2) if xpath else []
user_answer = []
for item1, item2 in zip(items1, items2):
user_answer.append(item1)
user_answer.append(item2)
# user_answer[0] = item1
# user_answer[1] = item2
self.evaluate_answer(scoring, user_answer, right_answer, points)
if scoring['points'] > 0:
break
# 사용자 입력값이 mm단위인 경우
elif "mmSize" in (category or ""):
elif (category or "") == "mmSize":
items = root.xpath(xpath)
error_range = criterion.get('tolerance', 0)
@@ -325,7 +330,7 @@ class XMLScorer:
if scoring['points'] > 0:
break
elif "ParaShape" in (category or ""):
elif (category or "") == "ParaShape":
items = root.xpath(xpath)
for item in items:
@@ -341,7 +346,7 @@ class XMLScorer:
break
# Boolean 타입 정답인 경우
elif "Boolean" in (category or ""):
elif (category or "") == "Boolean":
items = root.xpath(xpath)
items2 = root.xpath(xpath2) if xpath2 else False
@@ -350,23 +355,23 @@ class XMLScorer:
self.evaluate_answer(scoring, user_answer, right_answer, points)
# 채점기준표 파일에 작성된 rgb값을 그대로 읽어와 HML파일 요소의 int형 rgb값과 비교
elif "Color" in (category or ""):
items = root.xpath(xpath)
elif (category or "") == "Color":
items = root.xpath(xpath) if xpath else []
items2 = root.xpath(xpath2) if xpath2 else []
rgb_text = right_answer
r, g, b = map(int, rgb_text.split(','))
rgb_int = (b << 16) + (g << 8) + r
for item in items:
# items, items2를 순차적으로 순회
for item in chain(items, items2):
user_answer = int(item)
self.evaluate_answer(scoring, user_answer, rgb_int, points, method="equal")
if scoring['points'] > 0:
break
# 문단 첫글자 장식 채점
elif "TwoLineSize" in (category or ""):
elif (category or "") == "TwoLineSize":
items = root.xpath(xpath)
error_range = criterion.get('tolerance', 0)
for item in items:
@@ -380,26 +385,60 @@ class XMLScorer:
break
# 폰트명
elif "FontName" in (category or ""):
charshape_id = root.xpath(xpath)
elif (category or "") == "FontName":
charshape_list = root.xpath(xpath)
if not charshape_id:
charshape_id = None
user_answer = None
user_answer = ""
else:
font_id = root.xpath(f"//CHARSHAPE[@Id='{charshape_id[0]}']/FONTID/@Hangul")
font_name = root.xpath(f"//FONTFACE[@Lang='Hangul']/FONT[@Id='{font_id[0]}']/@Name")
user_answer = font_name[0]
for charshape_id in charshape_list:
font_id = root.xpath(f"//CHARSHAPE[@Id='{charshape_id}']/FONTID/@Hangul")
font_name = root.xpath(f"//FONTFACE[@Lang='Hangul']/FONT[@Id='{font_id[0]}']/@Name")
user_answer = font_name[0]
# 폰트 "견고딕"과 "중고딕"은
# 한글프로그램 내부적으로 "한양견고딕", "한양중고딕"으로 저장되므로
# 수험자 답변에서 "한양"을 제거
if right_answer in ["견고딕", "중고딕"]:
user_answer = user_answer.replace("한양", "")
self.evaluate_answer(scoring, user_answer, right_answer, points, method="equal")
if scoring['points'] > 0:
break
# 폰트 "견고딕"과 "중고딕"은
# 한글프로그램 내부적으로 "한양견고딕", "한양중고딕"으로 저장되므로
# 수험자 답변에서 "한양"을 제거
if right_answer in ["견고딕", "중고딕"]:
user_answer = user_answer.replace("한양", "")
# 테이블 폰트명
# 테이블 내부 모든 셀의 폰트가 정답과 일치해야 함
elif (category or "") == "TableFontName":
charshape_list = root.xpath(xpath)
# 문자속성이 없는 경우
if not charshape_list:
user_answer = ""
self.evaluate_answer(scoring, user_answer, right_answer, points, method="equal")
else:
all_match = True # 모든 항목이 정답과 일치해야 함
for charshape_id in charshape_list:
font_id = root.xpath(f"//CHARSHAPE[@Id='{charshape_id}']/FONTID/@Hangul")
font_name = root.xpath(f"//FONTFACE[@Lang='Hangul']/FONT[@Id='{font_id[0]}']/@Name")
self.evaluate_answer(scoring, user_answer, right_answer, points, method="equal")
user_answer = font_name[0]
# 내부 저장된 접두어 제거
if right_answer in ["견고딕", "중고딕"]:
user_answer = user_answer.replace("한양", "")
if user_answer != right_answer:
all_match = False
break # 하나라도 다르면 바로 오답 처리
if all_match:
self.evaluate_answer(scoring, user_answer, right_answer, points, method="equal")
else:
self.evaluate_answer(scoring, user_answer, right_answer, 0, method="equal") # 오답 처리
# 폰트 속성
elif "FontAttribute" in (category or ""):
elif (category or "") == "FontAttribute":
charshape = root.xpath(xpath)
if not charshape:
charshape = None
@@ -491,6 +530,7 @@ class XMLScorer:
self.evaluate_answer(scoring, user_answer, right_answer, points, method="equal")
# 한자
elif "Hanja" in (category or ""):
word_list = criterion.get('word', [])
@@ -516,9 +556,27 @@ class XMLScorer:
user_answer = min(score, max_score)
self.evaluate_answer(scoring, user_answer, right_answer, points, method="partial_score")
elif (category or "") == "chart_type":
chart_type_list = {
'꺾은선형': "//c:lineChart",
'가로막대형': "//c:barChart[c:barDir[@val='bar']]",
'세로막대형': "//c:barChart[c:barDir[@val='col']]",
'원형': "//c:pieChart",
'분산형': "//c:scatterChart"
}
chart_type = criterion.get('chart_type').replace(" ","")
if "묶은" in chart_type:
chart_type = chart_type.replace("묶은", "")
chart_xpath = chart_type_list[chart_type]
user_answer = bool(chart_tree.xpath(chart_xpath, namespaces=namespaces))
self.evaluate_answer(scoring, user_answer, right_answer, points)
# 문항 채점 결과를 리스트에 입력
onePersonResult['score_results'].append(scoring)
print(f'scoring: {scoring}')
onePersonResult['partial_scores'].append({
'section': section_id,
'score': self.partial_score