요즘 파이썬으로 공부하면서 그동안 필요했던 기능들을 파이썬으로 구현중인데, 배운 지 얼마 안됐지만 파이썬 언어 자체가 정말 매력적이네요
C++ 과는 비교가 안될 정도로 코딩량도 적고 로직에 집중할 수 있어 좋은 듯.
예제 코드의 목적
안드로이드 프로젝트가 커지면서 사용하지 않는 클래스가 점점 늘어남, 다른 파일에서 호출하지 않는 클래스를 찾기 위해 만듦
1. 모든 파일에서 클래스 이름을 찾아 저장 (한 파일에서 하나의 public class 만 있다고 가정)
2. 다시 모든 파일을 단어 단위로 읽어 '1' 에서 저장한 클래스 이름이 있으면 ref count 를 증가 시킴. (단, 클래스가 선언된 파일은 ref count 에서 제외
3. 참조하는 파일 리스트도 저장
4. csv 로 저장할 수 있도록 ',' 형식으로print --> 긁어서 메모장 같은데서 대충 편집 후 엑셀에서 불러와 ref count 0 인 클래스 확인 가능
import os
import codecs # utf-8 읽어 오기 위해
import re
gfilemap = {}
defPath = "c:\\myProject\\"
# key : class name value : path, ref count, ref path
gclassmap = {}
splitText = '[ .()[:<>,\t\n]'
def listallFile(path) :
for fname in os.listdir(path) :
fullname = os.path.join(path, fname)
if os.path.isdir(fullname) :
listallFile(fullname)
else:
gfilemap[fullname] = [fname, 0]
def readClassinJavaFile(path, isUTF8):
f = None
if (isUTF8):
f = codecs.open(path, "r", 'utf-8')
else:
f = open(path, "r")
while True:
line = ""
try:
line = f.readline()
except:
print("코드파일 읽기 실패", path)
return False;
if not line : break;
if line.find('public class ') < 0 :
continue
# 주석이면 skip
if line.find('//') == 0 :
continue
# llist = line.split()
llist = re.split(splitText, line)
classname = ''
for i in range(len(llist)) :
if llist[i] == 'class':
classname = llist[i+1]
break;
if len(classname) == 0:
continue
if classname in gclassmap.keys() :
print('중복 클래스' , classname)
classname = classname.replace('\n','')
gclassmap[classname] = [path, 0, None]
print(classname, path)
return True # 한 파일에서 하나만 처리
f.close()
return True
def readClassRefinJavaFile(path, isUTF8):
f = None
if (isUTF8):
f = codecs.open(path, "r", 'utf-8')
else:
f = open(path, "r")
while True:
line = ""
try:
line = f.readline()
except:
print("코드파일 읽기 실패", path)
return False;
if not line : break;
# 주석이면 skip
if line.find('//') == 0 :
continue
llist = re.split(splitText, line)
for name in llist:
if name in gclassmap.keys():
# 파일이 동일 하지 않은 경우만 Ref count++ 한다
if (gclassmap[name][0] != path) :
gclassmap[name][1] += 1;
# 클래스를 Ref 한 소스 리스트를 추가한다
# 중복을 피하기 위해 set() 으로 구성
if (gclassmap[name][2] == None) :
gclassmap[name][2] = set()
gclassmap[name][2].add(path)
continue;
f.close()
return True
if __name__ == "__main__":
listallFile(defPath)
for key, value in gfilemap.items():
if readClassinJavaFile(key,False) == False:
readClassinJavaFile(key, True)
for key, value in gfilemap.items():
if readClassRefinJavaFile(key,False) == False:
readClassRefinJavaFile(key, True)
print('class ref count 정리')
print('class,path,ref count,ref path')
for key, value in gclassmap.items():
i = 0
path = ''
for p in value[2]:
path += p
path += ' | '
i += 1
if (i > 5):
break;
msg = '%s,%s,%s,%s'%(key,value[0],value[1], path)
print(msg)
splitText = '[ .()[:<>,\t\n]'
llist = re.split(splitText, line)
for i in range(len(llist)) :
단어 단위 분리는 re.split 을 이용했습니다.
gclassmap[classname] = [path, 0, None]
클래스 이름을 key 로 해서 딕셔너리를 구성했는데 key,value[] 는 요런 식입니다.
key(클래스이름) = [클래스가 있는 파일 path, 참조 카운터, 참조하는 파일들(set)]
C++ 같으면 작은 아이템이라도 서로 다른 변수형을 담기 위해 항상 구조체/클래스부터 선언해야 하는데 그럴 필요가 없어서 확실히 코딩량이 줄어드네요
for name in llist:
if name in gclassmap.keys():
# 파일이 동일 하지 않은 경우만 Ref count++ 한다
if (gclassmap[name][0] != path) :
gclassmap[name][1] += 1;
# 클래스를 Ref 한 소스 리스트를 추가한다
# 중복을 피하기 위해 set() 으로 구성
if (gclassmap[name][2] == None) :
gclassmap[name][2] = set()
gclassmap[name][2].add(path)
continue;
key[name] 에 해당하는 value 배열의 [1] 값을 1 증가 시킵니다. 요것도 C++ 사용자에게는 조금 낯선 표현인데, 확실히 편하긴 하네요 (단 [1] [2] 식으로 표현하니 변수 명으로 이름을 파악할 수가 없어서 가독성은 조금 떨어지는 듯.
'개발 > 파이썬' 카테고리의 다른 글
[파이썬] 폴더 크기 구하기 (0) | 2017.12.30 |
---|---|
[파이썬] 리스트/딕셔너리 정렬하기 (0) | 2017.12.11 |
[파이썬] Creon Plus 를 이용해서 KOSPI200 종목 시세 가져오기 (0) | 2017.10.15 |
[파이썬] 폴더 명 일괄 변경 예제 (0) | 2017.10.11 |
[파이썬] 주어진 폴더 파일/크기 비교 예제 (0) | 2017.10.11 |
파이썬 기본 - 리스트/딕셔너리/튜플/set 기본 사용법 (0) | 2017.09.26 |
댓글