1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
|
import re
import os
import shutil
pattern = 'a-zA-Z0-9_\-\.\+\, '
Dir = r'D:\NEWManga' # \ 는 특수문자 할때 쓰는거라 에러 ex) \n, 따라서 raw로 해석안하고 읽으라고 r, 아니면 \\
p = re.compile('\[[a-zA-Z0-9_\-\.\+\,\! ]*\]', re.IGNORECASE)
p2 = re.compile('\[[a-zA-Z0-9_\-\.\+\,\! ]*\([a-zA-Z0-9_\-\.\+\,\! ]*\)\]', re.IGNORECASE)
p3 = re.compile('\([a-zA-Z0-9_\-\.\+\,\! ]*\)', re.IGNORECASE)
def search(dirname):
filenames = os.listdir(dirname)
names = []
for filename in filenames:
m = p.search(filename)
m2 = p2.search(filename)
full_filename = os.path.join(dirname, filename)
ext = os.path.splitext(filename)[-1]
if ext == '':
continue
name = ''
name2 = ''
if m != None:
name = m.group()[1:-1]
if m2 != None:
name2 = p3.search(m2.group())
name2 = name2.group()[1:-1]
if name.upper() == 'KOREAN' or name.upper() == 'DIGITAL' or name == '' or name == ' ':
if not (name2.upper() == 'KOREAN' or name2.upper() == 'DIGITAL' or name2 == '' or name2 == ' '):
name = name2
else:
continue
try:
if not name == '':
if not os.path.isdir(os.path.join(dirname, name)):
os.mkdir(os.path.join(dirname, name))
shutil.move(full_filename, os.path.join(dirname, name))
except:
pass
Dir = input('directory : ')
search(Dir)
|
cs |
이런 코드입니다. 패턴대로 분류해서 폴더 만들고 그 안에 정리해주는 식의 코드인데, 정규식 사용이 너무 어렵네요...용도는 신사분들이라면 코드를 보자마자 바로 알아채실거라 생각합니다. 근데 저렇게 하나하나 패턴을 지정해놓으니까 일어나 한국어 등의 다른 패턴은 못 읽더라구요...이 코드를 어떻게 개선시킬지 질문드려봅니다.
정규표현식은 보기만 해도 엄청 어렵죠. 바빠서 길게는 못 쓰고, 몇 가지 팁만 생각나는 대로 좀 드리겠습니다.
1글자 이상의 모든 글자는 r".+"이고, 0글자 이상의 모든 글자는 r".*"입니다. 예를 들어 문자열 a = "[]"이고 문자열 b = "[asdf]"일 때, 정규식을 r"\[.+\]"이라고 넣으면 문자열 a는 안 잡히는데 문자열 b는 잡힙니다. 각괄호 안에 뭔가 들어 있느냐의 여부로 잡히고 말고가 결정되는 것이죠. 만약에 정규식이 r"\[.*\]"이면 문자열 a와 b가 모두 잡힙니다.
정규표현식을 검사할 수 있는 웹사이트로 https://regex101.com/ 이런 곳이 있습니다. 언어 설정을 Python으로 맞추고 사용해 보세요.
파이썬에는 fnmatch나 glob와 같은 모듈이 있습니다. 파일 이름 처리에 사용할 수 있지요.
파이썬에서는 어떤 문자열이 포함되어 있는지 여부를 확인하기 위해 굳이 문자열의 일부를 떼어다가 비교할 필요가 없습니다. 그냥 in이라는 연산자를 쓰면 되거든요. 예를 들어 "korea"라는 문자열이 "I am korean"이라는 문자열 안에 들어 있는지 알고 싶다면 if "korea" in "I am korean": # True면 할 일… 뭐 이런 식으로 사용할 수 있습니다. 이것도 마찬가지로 and나 or과 함께 쓸 수 있고요. 굳이 따로 떼어내려고 애쓸 필요가 없습니다. 물론 대소문자 문제야 upper()나 lower() 메소드로 적절히 처리해주면 되겠죠.
한 함수 안에서 너무 많은 것을 하려고 하는 것 같은데, 일부 기능을 더 작은 함수로 떼어내어 보는 것은 어떨까요? 이렇게 하면 한 함수 안에서 비슷비슷한 이름으로 된 변수들이 자꾸 늘어나는 것도 막을 수 있습니다. 지금은 search()라는 함수 안에서 이름과 달리 파일 이동까지 처리하고 있는데, 이렇게 하면 나중에 헷갈릴 수 있으니 파일 이동 부분을 따로 분리하는 것도 좋겠죠.
search() 함수 안의 names 배열은 사용하는 곳이 없는 것 같은데 삭제하는 게 어떨까요? 안 쓰는 변수가 들어가 있으면 괜히 헷갈리기만 합니다. 특히 지금처럼 비슷비슷한 변수 이름이 반복되는 상황에서는 더욱 그래요.
가능하다면 파일 이름을 표상하는 객체를 만들어서 사용해보는 것도 좋겠습니다. 파일 이름 안에 여러 개의 속성이 들어가 있는 상황이니, 이러한 속성을 묶어서 다루기 위해 객체를 사용하는 것이죠.
보아하니 딕셔너리나 튜플 같은 다른 자료구조를 부가적으로 사용할 수도 있겠습니다.
Dir이라는 문자열은 변수인데, 그렇다면 PEP 8 컨벤션에 따라 이름을 모두 소문자로 쓰는 것이 좋습니다. "dir" 이렇게 말이죠. 파이썬을 비롯한 많은 프로그래밍 언어에서 첫 글자를 대문자로 쓰는 경우는 클래스 이름을 지정하는 경우입니다. 그리고 파이썬에서는 변수명을 "lowercase_underscore" 이런 식으로 씁니다.
코드 앞쪽에서 Dir에 문자열을 넣어주고 있는데, 아래에서 input() 메소드를 쓰고 있네요. 이렇게 하면 앞쪽에서 어떤 문자열을 넣어줘도 코드 실행 시점에 사용자 입력으로 해당 문자열이 덮어씌워집니다. 아마도 아무것도 입력하지 않았을 때 어떤 기본값을 주고 싶었던 것 같은데, 그렇다면 dir = input("Input your value : ") or "Default value" 이런 식으로 하면 됩니다.