머릿말 채점 기준 수정
This commit is contained in:
20
.vscode/settings.json
vendored
Normal file
20
.vscode/settings.json
vendored
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
{
|
||||||
|
"cSpell.words": [
|
||||||
|
"AUTONUMFORMAT",
|
||||||
|
"BINITEM",
|
||||||
|
"borderfill",
|
||||||
|
"Borfer",
|
||||||
|
"BOTTOMBORDER",
|
||||||
|
"CELLZONE",
|
||||||
|
"charshape",
|
||||||
|
"chartxml",
|
||||||
|
"COLDEF",
|
||||||
|
"hwpx",
|
||||||
|
"PAGEMARGIN",
|
||||||
|
"PARASHAPE",
|
||||||
|
"SHAPEOBJECT",
|
||||||
|
"TEXTART",
|
||||||
|
"TEXTARTSHAPE",
|
||||||
|
"WINDOWBRUSH"
|
||||||
|
]
|
||||||
|
}
|
||||||
BIN
250908_DIW_2508D_TEST.xlsx
Normal file
BIN
250908_DIW_2508D_TEST.xlsx
Normal file
Binary file not shown.
BIN
250908_DIW_2508D_채점결과.xlsx
Normal file
BIN
250908_DIW_2508D_채점결과.xlsx
Normal file
Binary file not shown.
BIN
250908_DIW_2508D_채점결과_header.xlsx
Normal file
BIN
250908_DIW_2508D_채점결과_header.xlsx
Normal file
Binary file not shown.
@@ -259,7 +259,7 @@
|
|||||||
"searchValue": "DIAT",
|
"searchValue": "DIAT",
|
||||||
"value": "궁서",
|
"value": "궁서",
|
||||||
"points": 1,
|
"points": 1,
|
||||||
"category": "FontName.Header",
|
"category": "Header.FontName",
|
||||||
"item": "문구 (DIAT)/① 글꼴 (궁서)"
|
"item": "문구 (DIAT)/① 글꼴 (궁서)"
|
||||||
},
|
},
|
||||||
"26": {
|
"26": {
|
||||||
@@ -267,7 +267,7 @@
|
|||||||
"searchValue": "DIAT",
|
"searchValue": "DIAT",
|
||||||
"value": "900",
|
"value": "900",
|
||||||
"points": 1,
|
"points": 1,
|
||||||
"category": "OneAnswer.Header",
|
"category": "Header.OneAnswer",
|
||||||
"item": "문구 (DIAT)/② 크기 (9pt)"
|
"item": "문구 (DIAT)/② 크기 (9pt)"
|
||||||
},
|
},
|
||||||
"27": {
|
"27": {
|
||||||
@@ -275,7 +275,7 @@
|
|||||||
"searchValue": "DIAT",
|
"searchValue": "DIAT",
|
||||||
"value": "Right",
|
"value": "Right",
|
||||||
"points": 1,
|
"points": 1,
|
||||||
"category": "OneAnswer.Header",
|
"category": "Header.OneAnswer",
|
||||||
"item": "문구 (DIAT)/③ 정렬 (오른쪽 정렬)"
|
"item": "문구 (DIAT)/③ 정렬 (오른쪽 정렬)"
|
||||||
},
|
},
|
||||||
"28": {
|
"28": {
|
||||||
|
|||||||
@@ -5,6 +5,10 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"settings": {
|
"settings": {
|
||||||
"terminal.integrated.cwd": "${workspaceFolder}"
|
"terminal.integrated.cwd": "${workspaceFolder}",
|
||||||
|
"cSpell.words": [
|
||||||
|
"hwpx",
|
||||||
|
"PAGEMARGIN"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
115
diwScoring2.py
115
diwScoring2.py
@@ -133,10 +133,36 @@ class XMLScorer:
|
|||||||
|
|
||||||
# 하나의 XML 파일 채점
|
# 하나의 XML 파일 채점
|
||||||
def _score_xml_file(self, xml_file, chart_xml):
|
def _score_xml_file(self, xml_file, chart_xml):
|
||||||
|
# def parse_pages_by_bookmark(root):
|
||||||
|
# """
|
||||||
|
# P/TEXT/BOOKMARK 구조를 가진 XML에서 페이지 구간별 <P> 요소를 파싱하여 반환
|
||||||
|
# """
|
||||||
|
# pages = {}
|
||||||
|
# all_p_tags = root.xpath('//P')
|
||||||
|
|
||||||
|
# current_page = None
|
||||||
|
# page_start_index = None
|
||||||
|
|
||||||
|
# for i, p in enumerate(all_p_tags):
|
||||||
|
# # BOOKMARK가 존재하는지 확인 (어디에 있든 탐색)
|
||||||
|
# bookmarks = p.xpath('.//BOOKMARK')
|
||||||
|
# for bm in bookmarks:
|
||||||
|
# name = bm.get('Name')
|
||||||
|
# if name and name.endswith('_start'):
|
||||||
|
# current_page = name.replace('_start', '')
|
||||||
|
# page_start_index = i
|
||||||
|
# elif name and name.endswith('_end') and current_page is not None:
|
||||||
|
# page_end_index = i
|
||||||
|
# page_content = all_p_tags[page_start_index:page_end_index + 1]
|
||||||
|
# pages[current_page] = page_content
|
||||||
|
# current_page = None
|
||||||
|
# page_start_index = None
|
||||||
|
|
||||||
|
# return pages
|
||||||
def parse_pages_by_bookmark(root):
|
def parse_pages_by_bookmark(root):
|
||||||
"""
|
"""
|
||||||
P/TEXT/BOOKMARK 구조를 가진 XML에서 페이지 구간별 <p> 요소를 파싱하여 반환
|
BOOKMARK(Name="Page_X_start" ~ "Page_X_end") 사이의 <P> 요소들을
|
||||||
|
페이지 단위로 딕셔너리에 저장
|
||||||
"""
|
"""
|
||||||
pages = {}
|
pages = {}
|
||||||
all_p_tags = root.xpath('//P')
|
all_p_tags = root.xpath('//P')
|
||||||
@@ -145,15 +171,16 @@ class XMLScorer:
|
|||||||
page_start_index = None
|
page_start_index = None
|
||||||
|
|
||||||
for i, p in enumerate(all_p_tags):
|
for i, p in enumerate(all_p_tags):
|
||||||
# BOOKMARK가 존재하는지 확인
|
# P 안의 모든 BOOKMARK 탐색
|
||||||
bookmark = p.xpath('./TEXT/BOOKMARK')
|
bookmarks = p.xpath('.//BOOKMARK')
|
||||||
if bookmark:
|
for bm in bookmarks:
|
||||||
name = bookmark[0].get('Name')
|
name = bm.get('Name')
|
||||||
if name and name.endswith('_start'):
|
if name and name.endswith('_start'):
|
||||||
current_page = name.replace('_start', '')
|
current_page = name.replace('_start', '')
|
||||||
page_start_index = i
|
page_start_index = i
|
||||||
elif name and name.endswith('_end') and current_page is not None:
|
elif name and name.endswith('_end') and current_page is not None:
|
||||||
page_end_index = i
|
page_end_index = i
|
||||||
|
# 시작~끝까지 P 태그 묶음 저장
|
||||||
page_content = all_p_tags[page_start_index:page_end_index + 1]
|
page_content = all_p_tags[page_start_index:page_end_index + 1]
|
||||||
pages[current_page] = page_content
|
pages[current_page] = page_content
|
||||||
current_page = None
|
current_page = None
|
||||||
@@ -248,6 +275,25 @@ class XMLScorer:
|
|||||||
}
|
}
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
if "Header" in (category or ""):
|
||||||
|
def has_elements(ptags, xpath):
|
||||||
|
for p in ptags:
|
||||||
|
element_list = p.xpath(xpath) if xpath else []
|
||||||
|
if element_list:
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
page1_ptags = pages.get('Page_1', [])
|
||||||
|
page2_ptags = pages.get('Page_2', [])
|
||||||
|
header_xpath = "//HEADER//P"
|
||||||
|
has_page1_element = has_elements(page1_ptags, header_xpath)
|
||||||
|
has_page2_element = has_elements(page2_ptags, header_xpath)
|
||||||
|
|
||||||
|
if not has_page1_element or not has_page2_element:
|
||||||
|
user_answer = None
|
||||||
|
self.evaluate_answer(scoring, user_answer, right_answer, points, method="equal")
|
||||||
|
continue
|
||||||
|
|
||||||
if (category or "") == "PageSetting":
|
if (category or "") == "PageSetting":
|
||||||
items = root.xpath(xpath)
|
items = root.xpath(xpath)
|
||||||
error_range = criterion.get('tolerance', 0)
|
error_range = criterion.get('tolerance', 0)
|
||||||
@@ -418,26 +464,7 @@ class XMLScorer:
|
|||||||
|
|
||||||
# 정답이 하나인 경우
|
# 정답이 하나인 경우
|
||||||
# elif (category or "") in ["OneAnswer", "ChartOneAnswer"]:
|
# elif (category or "") in ["OneAnswer", "ChartOneAnswer"]:
|
||||||
elif "OneAnswer" in (category or ""):
|
elif "OneAnswer" in (category or ""):
|
||||||
if "Header" in category:
|
|
||||||
def has_elements(ptags, xpath):
|
|
||||||
for p in ptags:
|
|
||||||
charshape_list = p.xpath(xpath) if xpath else []
|
|
||||||
if charshape_list:
|
|
||||||
return True
|
|
||||||
return False
|
|
||||||
|
|
||||||
page1_ptags = pages.get('Page_1', [])
|
|
||||||
page2_ptags = pages.get('Page_2', [])
|
|
||||||
header_xpath = "//HEADER//P"
|
|
||||||
has_page1_element = has_elements(page1_ptags, header_xpath)
|
|
||||||
has_page2_element = has_elements(page2_ptags, header_xpath)
|
|
||||||
|
|
||||||
if not has_page1_element or not has_page2_element:
|
|
||||||
user_answer = ""
|
|
||||||
self.evaluate_answer(scoring, user_answer, right_answer, points, method="equal")
|
|
||||||
continue
|
|
||||||
|
|
||||||
items = root.xpath(xpath) if xpath else []
|
items = root.xpath(xpath) if xpath else []
|
||||||
items2 = root.xpath(xpath2) if xpath2 else []
|
items2 = root.xpath(xpath2) if xpath2 else []
|
||||||
|
|
||||||
@@ -580,26 +607,6 @@ class XMLScorer:
|
|||||||
|
|
||||||
# 폰트명
|
# 폰트명
|
||||||
elif "FontName" in (category or ""):
|
elif "FontName" in (category or ""):
|
||||||
# 'DIAT' 머릿말 문항 1,2페이지 둘 중 하나라도 없으면 0점 처리
|
|
||||||
if "Header" in category:
|
|
||||||
def has_charshape(ptags, xpath):
|
|
||||||
for p in ptags:
|
|
||||||
charshape_list = p.xpath(xpath) if xpath else []
|
|
||||||
if charshape_list:
|
|
||||||
return True
|
|
||||||
return False
|
|
||||||
|
|
||||||
page1_ptags = pages.get('Page_1', [])
|
|
||||||
page2_ptags = pages.get('Page_2', [])
|
|
||||||
header_xpath = "//HEADER//P"
|
|
||||||
has_page1_element = has_charshape(page1_ptags, header_xpath)
|
|
||||||
has_page2_element = has_charshape(page2_ptags, header_xpath)
|
|
||||||
|
|
||||||
if not has_page1_element or not has_page2_element:
|
|
||||||
user_answer = ""
|
|
||||||
self.evaluate_answer(scoring, user_answer, right_answer, points, method="equal")
|
|
||||||
continue
|
|
||||||
|
|
||||||
charshape_list = root.xpath(xpath)
|
charshape_list = root.xpath(xpath)
|
||||||
|
|
||||||
# 문자속성이 없는 경우
|
# 문자속성이 없는 경우
|
||||||
@@ -1313,19 +1320,19 @@ class XMLScorer:
|
|||||||
def main():
|
def main():
|
||||||
|
|
||||||
# 시험회차 및 유형
|
# 시험회차 및 유형
|
||||||
# exam_round = '2508'
|
exam_round = '2508'
|
||||||
exam_round = '2522'
|
# exam_round = '2522'
|
||||||
|
|
||||||
# 채점하고자 하는 유형은 주석 해제
|
# 채점하고자 하는 유형은 주석 해제
|
||||||
exam_types = [
|
exam_types = [
|
||||||
'A',
|
# 'A',
|
||||||
'B',
|
# 'B',
|
||||||
'C',
|
# 'C',
|
||||||
# 'D',
|
'D',
|
||||||
]
|
]
|
||||||
|
|
||||||
test_mode = False
|
# test_mode = False
|
||||||
# test_mode = True #/TEST 폴더 채점시
|
test_mode = True #/TEST 폴더 채점시
|
||||||
|
|
||||||
output_excel_paths = []
|
output_excel_paths = []
|
||||||
for exam_type in exam_types:
|
for exam_type in exam_types:
|
||||||
|
|||||||
87
회차별채점자료/2508/채점결과/git_branch_manage.md
Normal file
87
회차별채점자료/2508/채점결과/git_branch_manage.md
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
# GIT branch
|
||||||
|
|
||||||
|
## 📌 장기간 개발용 브랜치 전략
|
||||||
|
|
||||||
|
### 1. 메인(main) 브랜치
|
||||||
|
|
||||||
|
* 항상 **안정된 코드**
|
||||||
|
* 실제 서비스/라이브에서 사용하는 코드
|
||||||
|
* 여기서는 직접 실험하지 않음
|
||||||
|
|
||||||
|
### 2. 기능(feature) 브랜치
|
||||||
|
|
||||||
|
* 장기간 개발할 기능을 위한 브랜치
|
||||||
|
* 예시: `feature/new-parser`, `feature/ui-redesign`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📌 워크플로우
|
||||||
|
|
||||||
|
### 1. 기능 브랜치 생성
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git checkout main
|
||||||
|
git pull origin main # 최신화
|
||||||
|
git checkout -b feature/new-parser
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. 기능 개발 (여러 번 커밋)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 코드 수정
|
||||||
|
git add .
|
||||||
|
git commit -m "초기 버전: XML 파서 구조 추가"
|
||||||
|
```
|
||||||
|
|
||||||
|
* 계속 개발하면서 커밋 누적
|
||||||
|
* 필요하면 `git push origin feature/new-parser` 해서 원격에도 올려두기 (백업용)
|
||||||
|
|
||||||
|
### 3. 장기간 개발 중 main 따라가기 (동기화)
|
||||||
|
|
||||||
|
* main 브랜치가 바뀌면, 기능 브랜치로 가져와야 충돌 줄임
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git checkout main
|
||||||
|
git pull origin main
|
||||||
|
git checkout feature/new-parser
|
||||||
|
git merge main # main의 최신 내용 병합
|
||||||
|
```
|
||||||
|
|
||||||
|
⚡ 이 과정을 정기적으로 하면 `feature` 브랜치가 main과 멀어지지 않음
|
||||||
|
|
||||||
|
### 4. 기능 완료 → main에 병합
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git checkout main
|
||||||
|
git pull origin main
|
||||||
|
git merge feature/new-parser
|
||||||
|
git push origin main
|
||||||
|
```
|
||||||
|
|
||||||
|
### 5. 필요 시 브랜치 삭제
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git branch -d feature/new-parser
|
||||||
|
git push origin --delete feature/new-parser
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📌 네이밍 규칙 (혼자 관리할 때도 편리)
|
||||||
|
|
||||||
|
* `feature/기능명` : 장기간 개발용 (예: `feature/new-ui`)
|
||||||
|
* `fix/버그명` : 버그 수정용 (예: `fix/xml-encoding`)
|
||||||
|
* `test/실험명` : 단기 테스트용 (예: `test/xpath`)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
✅ 정리
|
||||||
|
|
||||||
|
* **main = 안정 코드**
|
||||||
|
* **feature 브랜치 = 장기간 개발용** (필요할 때 main과 동기화)
|
||||||
|
* 완료되면 main에 병합 → 안정화
|
||||||
|
* 이렇게 하면 실험/개발/운영 코드가 깔끔하게 분리됨
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
👉 기능 브랜치 개발 중에, **main 브랜치 변경분을 가져올 때** `merge` 방식이 편할까요, 아니면 `rebase` 로 깔끔하게 이력을 유지하는 게 좋을까요?
|
||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Reference in New Issue
Block a user