나도 솔직히 맘 놓고 공부하고 싶지만.....팀과제가 그걸 허락하지 않는걸....
folder = os.listdir('C:/Users/kevinkim/Desktop/results/') for index, folder_list in enumerate(folder, start = 1): print(f'질문: {index} 대답:{folder_list}') choose = input('혹시 다시 보고 싶은 답변이 있으시나요? 원하는 번호를 선택해 주세요!: ') for index, file_name in enumerate(folder, start = 1): new_file = os.path.join('C:/Users/kevinkim/Desktop/results/' + file_name) if index == int(choose): with open(new_file, 'r', encoding= 'utf-8') as file: file_content = file.read() file_name = file_name.split('_')[0] print(f"\n질문 : {file_name} \n대답 : {file_content}") break decision = input('''답변이 마음에 드셨나요? 1. 주제 다시 고르기 2. 나가기(quit) 3. 답변 삭제하기 ''') if decision in ['1', '주제 다시 고르기']: print('주제 고르기로 넘어갑니다') continue elif decision in ['2', 'quit', 'exit', 'out', '나가기']: print('즐거운 시간 되셨길 바랍니다!') break elif decision in ['3', '답변 삭제하기', '답변삭제하기']: folder = os.listdir('C:/Users/kevinkim/Desktop/results/') for index, file_name in enumerate(folder, start = 1): print(f'질문: {index} 대답:{file_name}') choose_file = input('삭제할 파일을 선택하세요!') for index, file_name in enumerate(folder, start = 1): if index == int(choose_file): new_file = os.path.join('C:/Users/kevinkim/Desktop/results/' + file_name) file_name = file_name.split('_')[0] os.remove(new_file) print('해당 답변은 삭제되었습니다') break else: print('정확한 주제를 골라주세요!') time.sleep(2) print('프로세스 다시 가동 중...') time.sleep(1) print('프로세스 가동완료...') time.sleep(1) continue query = input('질문을 입력하세요 : ') query = filename_preprocessing(query) if query.lower() in ['10', 'quit', 'exit', 'out', '나가기', '끄기']: print('이용해 주셔서 감사합니다.') break if query.lower() in ['back']: continue chat_history.add_user_message(query) duplicate_question = os.listdir('C:/Users/kevinkim/Desktop/prompt/') pattern = r'_\d{4}-\d{2}-d{2}_\d{2}_\d{2}$' duplicate_folder = [] for list in duplicate_folder: preprocessing_file = re.sub(pattern, '', duplicate_question) preprocessing_file = [file.replace('.txt', '') for file in preprocessing_file if file.endswith('.txt')] duplicate_folder.append(preprocessing_file) for text in duplicate_folder: try: if query.lower() in text: print('이미 물어본 질문입니다. 다른 질문을 해주세요') continue except Exception as e: print(f'에러발생: {e}')
하지만 팀 과제를 적을때도 배우는 것은 항상 있는 법.
re.sub에 대해 조금 더 알아가는 시간을 가졌다.
re.sub(pattern, repl, string, count=0, flags=0)
pattern
치환할 대상을 지정하는 정규 표현식 패턴입니다.
예: "a.b"는 "a"와 "b" 사이에 아무 문자 하나가 오는 문자열을 의미합니다.
repl
치환할 문자열 또는 함수입니다.
문자열일 경우: 패턴에 매칭된 부분이 이 문자열로 대체됩니다.
함수일 경우: 매칭된 객체를 입력으로 받아 대체 문자열을 반환합니다.
string
치환을 수행할 대상 문자열입니다.
count (기본값: 0)
치환할 최대 횟수를 지정합니다.
0일 경우: 문자열 전체에서 패턴을 찾고 모두 치환합니다.
flags
정규 표현식에서 추가적인 플래그를 지정합니다.
예: re.IGNORECASE(대소문자 무시), re.MULTILINE(여러 줄 매칭), re.DOTALL(줄바꿈 문자 포함 매칭) 등.
flags 사용법
기본
import re text = "apple banana apple" result = re.sub(r"apple", "orange", text) print(result) # orange banana orange
대소문자 무시text = "Apple apple APPLE" result = re.sub(r"apple", "fruit", text, flags=re.IGNORECASE) print(result) # fruit fruit fruit
함수 사용def replace_func(match): return match.group(0).upper() text = "hello world" result = re.sub(r"\w+", replace_func, text) print(result) # HELLO WORLD
치환 횟수 제한text = "one two three one two three" result = re.sub(r"one", "1", text, count=1) print(result) # 1 two three one two three
여러 줄 치환text = """Line1 Line2 Line3""" result = re.sub(r"^Line", "Row", text, flags=re.MULTILINE) print(result) # Row1 # Row2 # Row3
정규 표현식 기능
주요 메타 문자와 패턴 기호
1. 문자 관련 메타 문자
\w
단어 문자를 나타냅니다.
알파벳 대소문자, 숫자, 밑줄(_)을 포함합니다.
[a-zA-Z0-9_]와 동일한 의미.
예: "Hello_123"에서 \w+는 "Hello_123"과 매칭.
\W
단어 문자가 아닌 것을 나타냅니다.
[^a-zA-Z0-9_]와 동일한 의미.
예: "Hello, World!"에서 \W+는 ", " 및 "!"와 매칭.
\d
숫자를 나타냅니다.
[0-9]와 동일한 의미.
예: "abc123"에서 \d+는 "123"과 매칭.
\D
숫자가 아닌 것을 나타냅니다.
[^0-9]와 동일한 의미.
예: "abc123"에서 \D+는 "abc"와 매칭.
\s
공백 문자를 나타냅니다.
공백, 탭(\t), 줄바꿈(\n), 캐리지 리턴(\r) 등을 포함.
예: "a b\tc\nd"에서 \s는 " "와 "\t" 및 "\n"에 매칭.
\S
공백이 아닌 것을 나타냅니다.
예: "a b\tc\nd"에서 \S+는 "a", "b", "c", "d"에 매칭.
.
임의의 한 문자를 나타냅니다(줄바꿈 제외).
예: "a1 b2"에서 .는 각각 "a", "1", "b", "2"와 매칭.
2. 반복 패턴
*
0회 이상 반복을 나타냅니다.
예: "aaa"에서 a*는 "aaa"와 매칭.
+
1회 이상 반복을 나타냅니다.
예: "aaa"에서 a+는 "aaa"와 매칭.
?
0회 또는 1회 나타남을 의미합니다.
예: "abc"에서 ab?는 "ab"와 매칭.
{m,n}
반복 횟수를 지정합니다.
예: "aaa"에서 a{2,3}은 "aaa"와 매칭.
{m,}: 최소 m번 이상.
{,n}: 최대 n번까지.
주요 메타 문자와 패턴 기호
1. 문자 관련 메타 문자
\w
단어 문자를 나타냅니다.
알파벳 대소문자, 숫자, 밑줄(_)을 포함합니다.
[a-zA-Z0-9_]와 동일한 의미.
예: "Hello_123"에서 \w+는 "Hello_123"과 매칭.
\W
단어 문자가 아닌 것을 나타냅니다.
[^a-zA-Z0-9_]와 동일한 의미.
예: "Hello, World!"에서 \W+는 ", " 및 "!"와 매칭.
\d
숫자를 나타냅니다.
[0-9]와 동일한 의미.
예: "abc123"에서 \d+는 "123"과 매칭.
\D
숫자가 아닌 것을 나타냅니다.
[^0-9]와 동일한 의미.
예: "abc123"에서 \D+는 "abc"와 매칭.
\s
공백 문자를 나타냅니다.
공백, 탭(\t), 줄바꿈(\n), 캐리지 리턴(\r) 등을 포함.
예: "a b\tc\nd"에서 \s는 " "와 "\t" 및 "\n"에 매칭.
\S
공백이 아닌 것을 나타냅니다.
예: "a b\tc\nd"에서 \S+는 "a", "b", "c", "d"에 매칭.
.
임의의 한 문자를 나타냅니다(줄바꿈 제외).
예: "a1 b2"에서 .는 각각 "a", "1", "b", "2"와 매칭.
2. 반복 패턴
*
0회 이상 반복을 나타냅니다.
예: "aaa"에서 a*는 "aaa"와 매칭.
+
1회 이상 반복을 나타냅니다.
예: "aaa"에서 a+는 "aaa"와 매칭.
?
0회 또는 1회 나타남을 의미합니다.
예: "abc"에서 ab?는 "ab"와 매칭.
{m,n}
반복 횟수를 지정합니다.
예: "aaa"에서 a{2,3}은 "aaa"와 매칭.
{m,}: 최소 m번 이상.
{,n}: 최대 n번까지.
3. 위치 지정 패턴
^
문자열의 시작을 나타냅니다.
예: "Hello World"에서 ^Hello는 "Hello"와 매칭.
$
문자열의 끝을 나타냅니다.
예: "Hello World"에서 World$는 "World"와 매칭.
\b
단어 경계를 나타냅니다.
예: "Hello World"에서 \bWorld\b는 "World"와 매칭.
단어 경계는 알파벳과 공백 또는 특수 문자의 경계입니다.
\B
단어 경계가 아닌 부분을 나타냅니다.
예: "HelloWorld"에서 \BWorld는 "World"와 매칭.
4. 그룹화와 선택
()
하위 그룹을 지정합니다.
예: "abc123"에서 (abc)(123)는 두 그룹으로 매칭됩니다.
각 그룹은 .group(1), .group(2) 등으로 접근할 수 있습니다.
|
OR(또는)을 나타냅니다.
예: "cat", "dog" 중 하나를 매칭하려면 cat|dog를 사용합니다.
(?:...)
비캡처 그룹(결과 저장 안 함)을 만듭니다.
예: (?:abc)는 "abc"를 매칭하지만 결과에 저장되지 않음.
5. 특수 문자 이스케이프
\
메타 문자를 일반 문자로 취급하도록 이스케이프합니다.
예: .은 임의 문자지만 \.은 실제 점 문자로 인식됩니다.
6. 플래그 옵션
re.IGNORECASE (i): 대소문자 무시.
re.MULTILINE (m): ^와 $가 여러 줄에서 각각 작동.
re.DOTALL (s): .이 줄바꿈 문자까지 매칭.
이렇게 보니까 진짜 너무 많다.
pattern = r'_\d{4}-\d{2}-d{2}_\d{2}_\d{2}$' 이렇도 이렇게 각 안 숫자들에 맞게 없애주는 역할도 가능하다는것이 나는 솔직히 놀랐다. 게다가 os.path.join을 더 실감나게 쓸 수 있는 기회가 되기도 했다.(참고로 내일부터 조금 여유로워지 때문에 streamlit을 전체적으로 복습 시작!!)
오늘은 여기까지.....