import os import re import math import time import rarfile import zipfile import shutil import difflib import subprocess import UtilPack as util m_dbgLevel = 0 listDbgStr = [] # def IsEmptyStr(string): return 0 == len(string.strip()) # def GetCurrentTime(): # 현재 시간을 구하고 구조체로 변환 current_time_struct = time.localtime() # 구조체에서 연, 월, 일, 시간, 분, 초를 추출 year = current_time_struct.tm_year month = current_time_struct.tm_mon day = current_time_struct.tm_mday hour = current_time_struct.tm_hour minute = current_time_struct.tm_min second = current_time_struct.tm_sec strRet = (f"{year}/{month}/{day}_{hour}:{minute}:{second}") return strRet #for debug def DbgOut(strInput, bPrint = False): strMsg = (f"{GetCurrentTime()} : {strInput}") listDbgStr.append(strMsg) if True == bPrint: print(strMsg) def printDbgMessages(): for line in listDbgStr: print(line) # 입력된 패스에서 부모 폴더를 찾는다. 0 은 자기자신 1은 부모, 숫자대로 위로. def GetParentDirName(FullPath, nUp): parts = FullPath.split(os.sep) nTrgIdx = 0 if nUp < len(parts): nTrgIdx = len(parts) -nUp -1 elif nUp < 0: nTrgIdx = len(parts) - 1 else: nTrgIdx = 0 return parts[nTrgIdx] # os 모듈을 사용하여 자식 폴더를 반환 def GetSubDirectories(folder_path): subdirectories = [ d for d in os.listdir(folder_path) if os.path.isdir(os.path.join(folder_path, d))] return subdirectories # 입력된 경로의 자식 폴더를 찾아 반환한다. # 반환하는 리스트는 리커시브 - 손자, 증손자 폴더까지 전부 포함한다 def GetAllSubDirectories(root_dir): subdirectories = [] # root_dir에서 하위 디렉토리 및 파일 목록을 얻음 for dirpath, dirnames, filenames in os.walk(root_dir): # 하위 디렉토리 목록을 반복하며 하위 디렉토리만 추출 for dirname in dirnames: path = os.path.join(dirpath, dirname) if True == IsFinalFolder(path): subdirectories.append(path) return subdirectories def ListFileExtRcr(pathTrg, strExt): listRet= [] # pathTrg의 하위 디렉토리 및 파일 목록을 얻음 for dirpath, dirnames, filenames in os.walk(pathTrg): for file in filenames: extTmp = GetExtStr(file, False) if extTmp.lower() == strExt and file.startswith('.'): listRet.append(os.path.join(dirpath, file)) return listRet # 입력된 경로가 자식 폴더를 가지고 있는지 판단한다.- 최종 폴더인지 여부 # 자식이 없으면 True, 자식이 있으면 False def IsFinalFolder(path): bRet = True contents = os.listdir(path) for item in contents: if True == os.path.isdir(item): bRet = False break return bRet; # 어떤 경로 안에서 특정 확장자의 파일을 뽑아내어 그 리스트를 반환한다. def FindFileFromExt(path, ext): bDot = False if 0 <= ext.find('.'): bDot = True listRet = [] if False == os.path.exists(path): return listRet contents = os.listdir(path) for item in contents: if True == os.path.isdir(item): continue extItem = GetExtStr(item, bDot) if extItem.lower() == ext.lower(): listRet.append(item) return listRet # 파일 이름에서 확장자를 뽑아낸다. True : '.' 을 포함한다. def GetExtStr(file_path, bDot = True): retStr = "" # 파일 경로에서 마지막 점을 찾아 확장자를 추출 last_dot_index = file_path.rfind('.') if last_dot_index == -1: retStr = "" # 점이 없는 경우 확장자가 없음 else: if True == bDot: retStr = file_path[last_dot_index:] else: retStr = file_path[last_dot_index+1:] return retStr # 문자열에 포함된 단어를 지운다. def RmvSubString(mainString, subString): # 문자열에서 부분 문자열의 인덱스를 찾습니다. strIdx = mainString.find(subString) if strIdx == -1: # 부분 문자열이 존재하지 않으면 그대로 반환합니다. return mainString endIdx = strIdx + len(subString) # 부분 문자열을 제거하고 새로운 문자열을 반환합니다. return mainString[:strIdx] + mainString[endIdx:] def ExtractZIP(zip_file, extract_to): with zipfile.ZipFile(zip_file, 'r') as zf: zf.extractall(extract_to) # def CreateZIP(output_zip, *files): with zipfile.ZipFile(output_zip, 'w') as zf: for file in files: pathTemp = os.path.join('root', os.path.basename(file)) zf.write(file, pathTemp) bRet = False if os.path.exists(output_zip): bRet = True return bRet # 파일 리스트에 들어있는 파일만 골라서 압축을 합니다. 상대경로를 제거하는게 기본값. def CreateZIPShell(zipName, *files, bRmvRPath = True): command = "zip " if True == bRmvRPath: command += "-j " command += f"\"{zipName}\" " # 이중 리스트인 이유를 모르겠다. for file in files: strTemp = "" if isinstance(file, list): strTemp = ' '.join(file) else: strTemp = f"\"{file}\" " command += strTemp # for item in file: # command += f"\"{item}\" " result = subprocess.run(command, shell=True, capture_output=True, text=True) bRet = False if 0 == result.returncode: bRet = True return bRet # 특정 확장자만 쉘을 이용해서 압축한다 def CreateZIPShExt(zipName, TrgExt): command = f"zip -j {zipName} *.{TrgExt}" result = subprocess.run(command, shell=True, capture_output=True, text=True) bRet = False if 0 == result.returncode: bRet = True return bRet # JSON 을 트리 구조로 출력한다. def PrintJSONTree(data, indent=0): if isinstance(data, dict): for key, value in data.items(): print(' ' * indent + str(key)) PrintJSONTree(value, indent + 1) elif isinstance(data, list): for item in data: PrintJSONTree(item, indent) else: print(' ' * indent + str(data)) # 세로 크기를 가로 비율대로 줄여서 반환 (가로를 기준으로 세로 길이) def GetRSzHeight(nWidth, nHeight, nTrgW): if nWidth <= 0 or nTrgW <= 0: return 0; fRatio = nTrgW / nWidth nTrgH = round(nHeight * fRatio) return nTrgH # 가로 크기를 세로 비율대로 줄여서 반환 (세로를 기준으로 가로 길이) def GetRSzWidth(nWidth, nHeight, nTrgH): if nHeight <= 0 or nTrgH <= 0: return 0; fRatio = nTrgH / nHeight nTrgW = round(nWidth * fRatio) return nTrgW # 엑셀 열 너비는 약 7.5픽셀 단위 # 엑셀 행 높이는 약 25픽셀 단위 # 이대로는 사이즈가 안 맞아서 적당히 곱해줌 def GetCellSize(nImgW, nImgH, DPI = 96): column_width = (nImgW / DPI) * 7.5 * 2 row_height = (nImgH / DPI) * 25 * 3 return column_width, row_height def GetSheetInfoValue(text): if text is None: return "", "" pattern = r'<(.*?)>' matches = re.findall(pattern, text) cleaned = re.sub(pattern, '', text) return cleaned, matches # 두 GPS 좌표 간 거리 구하기 (미터) def GetDistanceGPS(lat1, lon1, lat2, lon2): # 지구의 반지름 (단위: 미터) R = 6371008.8 # 위도와 경도를 라디안으로 변환 lat1 = math.radians(lat1) lon1 = math.radians(lon1) lat2 = math.radians(lat2) lon2 = math.radians(lon2) # 차이 계산 dlat = lat2 - lat1 dlon = lon2 - lon1 # Haversine 공식 적용 a = math.sin(dlat / 2)**2 + math.cos(lat1) * math.cos(lat2) * math.sin(dlon / 2)**2 c = 2 * math.atan2(math.sqrt(a), math.sqrt(1 - a)) # 거리 계산 distance = R * c return distance