한패 원제작자분.. 르낭님으로부터 연락이 드디어 닿았다!
보내주신 파일을 하나하나 뜯어보는데 경외감만이 들었다. 이걸 하셨다고?ㄷㄷ
무튼 내가 하고자 하는 것은 기존 한패 스크립트를 리메이크 스크립트로 이식하는 것.
omsg방식으로 뽑아낸 리메이크판 스크립트.
![24b0d121e09c28a8699fe8b115ef046f5c4d989faf]()
그리고 이건 오리지널 한패 완역 스크립트.
![24b0d121e09c28a8699fe8b115ef046ecb40c2f325]()
구조가 다르다. 물론 리메이크판 스크립트를 이런 구조로 뽑을 수 있지만, 막상 해보니 선택지 및 live2d관련 스크립트에 문제가 발생하게 되더라.
무튼.. 이걸 하나하나 긁어서 붙이는건 말도 안되는 행위라 판단..
1. 오리지널 한패 스크립트의 전처리.
import os
import sys
def preprocess_file_b(file_b_name):
# 파일 체크
if not os.path.isfile(file_b_name):
print(f"에러: {file_b_name} 를 찾을 수 없습니다.")
return
# 인코딩 확인
with open(file_b_name, 'r', encoding='utf-8') as file_b:
file_b_contents = file_b.readlines()
# 수정된 라인용 어레이
modified_lines = []
i = 0
while i < len(file_b_contents):
line_with_prefix = file_b_contents[i].lstrip('/').split('>>')[-1].strip()
if i + 1 < len(file_b_contents):
translated_line = file_b_contents[i + 1].lstrip('/').split('>>')[-1].strip()
else:
translated_line = ""
if '「' in line_with_prefix:
line_before_quote, line_after_quote = line_with_prefix.split('「', 1)
translated_before_quote, translated_after_quote = translated_line.split('「', 1)
if line_before_quote.strip(): # 괄호 앞 부분이 비었는지 체크 (인물 이름 없는 대사)
modified_lines.append('//' +line_before_quote)
modified_lines.append( translated_before_quote)
modified_lines.append('//「' +line_after_quote)
modified_lines.append('「' + translated_after_quote)
i += 2 # 원문, 번역문 두 줄 다 처리했으므로 한 줄 패스
elif '浩平(' in line_with_prefix:
line_before_quote, line_after_quote = line_with_prefix.split('(', 1)
translated_before_quote, translated_after_quote = translated_line.split('(', 1)
modified_lines.append('//' +line_before_quote)
modified_lines.append( translated_before_quote)
modified_lines.append('//(' +line_after_quote)
modified_lines.append('(' + translated_after_quote)
i += 2 # 원문, 번역문 두 줄 다 처리했으므로 한 줄 패스
else:
modified_lines.append('//' +line_with_prefix)
modified_lines.append(translated_line)
i += 2 # 원문, 번역문 두 줄 다 처리했으므로 한 줄 패스
# _processedB 붙여 저장
base_name, _ = os.path.splitext(file_b_name)
processed_file_b_name = f"{base_name}_processedB.txt"
with open(processed_file_b_name, 'w', encoding='utf-8') as processed_file_b:
processed_file_b.writelines(line + '\n' for line in modified_lines)
return processed_file_b_name
if __name__ == '__main__':
if len(sys.argv) != 2:
print("one 오리지널 번역문 스크립트 전처리기. 사용법: python one_process01.py originalscript.dg")
sys.exit(1)
file_b_name = sys.argv[1]
preprocess_file_b(file_b_name)
![24b0d121e09c28a8699fe8b115ef046f5c4c9c96a0]()
00000>>를 지워줬고,
// 00011>> 浩平「…6時…半か?」
00011>> 코헤이「…6시…반이라고?」
이렇게 한 줄로 된 대사를
//浩平
코헤이
//「…6時…半か?」
「…6시…반이라고?」
이렇게 바꿔줬다. 이래야 이후 작업이 가능해진다.
2. 스크립트 이식
1. 한패 스크립트는 원문도 반각문자로 되어 있는 반면 리메이크 원본 스크립트는 당연히 전각문자를 쓴다. 이 부분 대응 필요.
2. 인물/대사 분리
// 00680>> 浩平「…オレも帰るか」
00680>> 코헤이「…나도 가야지」
이런 일반적인 대사 말고도
// 00693>> 浩平(運動部の連中もさすがに休みか…)
00693>> 코헤이(운동부도 오늘은 쉬는 건가…)
이렇게 괄호 처리된 독백도 있다. 따라서 모든 「 뿐만 아니라 주인공 이름 뒤에 붙는( 이런 괄호도 처리해줘야 한다.
3. 인물 없는 대사 처리
인물 이름 없이 대사만 있는 라인도 있다.
// 00698>> 「…くしゅん」
00698>> 「…엣취」
4. 오리지널 한패 스크립트는 UTF-8, 리메이크 스크립트는 UTF-8-BOM이다. 인코딩 맞춰 불러오고, 맞춰서 저장되어야 함.
5. 리메이크 스크립트는 \@ 이런게 뒤에 붙어있는 경우가 있음.
import os
import sys
import codecs
import threading
import re
class TimeoutException(Exception):
pass
def normalize_line(line):
# 특수문자 처리
line = line.replace('、', ', ').replace('。', '.').replace('?', '?').replace('!', '!').replace('「', '').replace('」', '').replace('『', '').replace('』', '').replace('(', '').replace(')', '').replace(' ', '').replace(',', ', ').replace('.', '. ')
return re.sub(r'\s+', ' ', line.strip())
def transfer_lines(file_a_name, file_b_name, timeout=60):
# 파일 체크. file_a는 리메이크 스크립트, file_b는 전처리된 오리지널 한패 스크립트
if not os.path.isfile(file_a_name):
print(f"에러: {file_a_name} 를 찾을 수 없습니다.")
return
if not os.path.isfile(file_b_name):
print(f"에러: {file_b_name} 를 찾을 수 없습니다.")
return
# 타임아웃
timer = threading.Timer(timeout, raise_timeout)
try:
timer.start()
# 인코딩 적용하여 파일 열기
with codecs.open(file_a_name, 'r', encoding='utf-8-sig') as file_a, codecs.open(file_b_name, 'r', encoding='utf-8') as file_b:
file_a_contents = file_a.readlines()
file_b_contents = file_b.readlines()
# 라인 리스트 생성
modified_lines = []
# 원문-번역문 매핑 리스트 생성
translation_mapping = {}
# 전처리된 오리지널 한패 스크립트 반복처리
i = 0
while i < len(file_b_contents):
if file_b_contents[i].startswith('//'):
original_line = normalize_line(file_b_contents[i][2:].strip())
if i + 1 < len(file_b_contents):
translated_line = file_b_contents[i + 1].strip().replace(' ', '')
translation_mapping[original_line] = translated_line
i += 2
else:
i += 1
else:
i += 1
# 리메이크 스크립트 반복처리
for line_a in file_a_contents:
# 공백제거
leading_whitespace = re.match(r'^(\s*)', line_a).group(1)
# \@로 끝나는 라인 체크
ends_with_at = line_a.strip().endswith('\\@')
# 해당 라인 정규화
line_a_normalized = normalize_line(line_a.strip().rstrip('\\@'))
# 매핑 리스트에 정규화된 라인 있는지 확인
if line_a_normalized in translation_mapping:
translated_line = translation_mapping[line_a_normalized]
# 공백, \@ 및 번역문 적용
if ends_with_at:
modified_lines.append(leading_whitespace + translated_line + '\\@\n')
else:
modified_lines.append(leading_whitespace + translated_line + '\n')
else:
# 번역 매핑 못찾을 경우 원문 그대로 두기
modified_lines.append(line_a)
except TimeoutException:
print("타임아웃. 파일에 문제가 있을 수 있습니다. 전처리가 제대로 되었는지 확인이 필요합니다.")
except Exception as e:
print(f"에러: {e}")
finally:
timer.cancel()
base_name = os.path.splitext(file_a_name)[0]
processed_file_name = f"{base_name}_processed.txt"
with codecs.open(processed_file_name, 'w', encoding='utf-8-sig') as processed_file:
processed_file.writelines(modified_lines)
print(f"오리지널 한패 스크립트 {file_b_name} 내용을 반영, {processed_file_name} 로 저장하였습니다.")
def raise_timeout():
raise TimeoutException("타임아웃.")
if __name__ == '__main__':
if len(sys.argv) != 3:
print("one 오리지널 번역문 스크립트 to one 리메이크 스크립트 변환기. 오리지널 번역문 전처리가 필요합니다.")
print("사용법: python one_process02.py remake_script.txt originalscript_processedB.txt")
sys.exit(1)
file_a_name = sys.argv[1]
file_b_name = sys.argv[2]
transfer_lines(file_a_name, file_b_name)
![24b0d121e09c28a8699fe8b115ef046f5c4c9998ac]()
신난다!
오리지널 스크립트 구조상 선택지까지 번역하기는 어려우므로 저정도는 직접 만지는걸로.
오리지널에서 男子学生였던 이름이 리메이크에서 男子学生A가 되는 등 소소한 차이점이 있어 검수하며 잡아가야 할 것 같다.
이로써 파일로만 118개, 만줄에 육박하는 스크립트 복붙 노가다를 하지 않아도 된다!
아 물론 이렇다고 한패가 막 금방 나오는건 아닙니다. 앞으로 무슨 문제가 생길지 모름
도와주시는 모든 분들께 무한 감사드립니다.
그럼 자러
와 진짜 개노가다
화이팅!
응원합니다
한패의 명맥이 끊어지지 않았다니
응원하고있습니다 - dc App
사랑해