본문 바로가기
🐍Python

[20210802] Python 기본 문법 6 - 라이브러리 2, 정규식, numpy

by 캔 2021. 8. 2.

라이브러리

지난 글에 이어서 주요 라이브러리에 대해 살펴보려고 한다.

# tempfile: 파일을 임시로 만들어서 사용할 때 유용한 모듈.
# tempfile.mkstemp()는 중복되지 않는 임시파일의 이름을 무작위로 만들어서 리턴
import tempfile

filename = tempfile.mkstemp()
print(filename)

# 임시 저장 공간으로 사용할 파일 객체를 돌려준다.
# 기본적으로 바이너리 쓰기 모드(wb)를 갖는다.
# f.close()가 호출되면 이 파일 객체는 사라진다.
import tempfile

f = tempfile.TemporaryFile()
print(f)
f.close()

# time
# time.time(): UTC(Universal Time Coordinated, 협정 세계 표준시)를 사용하여 현재 시간을
# 실수 형태로 리턴한다. 1970년 1월 1일 0시 0분 0초를 기준으로 지난 시간을 초 단위로 리턴한다.
import time

a = time.time()
print(a)

# time.localtime(): time.time()이 리턴한 실수 값을 연도, 월, 일, 시, 분, 초... 형태로 리턴.
b = time.localtime(a)
print(b)

# time.asctime(): time.localtime()이 리턴한 튜플 형태의 값을 인수로 받아서
# 날짜, 시간을 알아보기 쉬운 형태로 리턴
c = time.asctime(b)
print(c)

# time.ctime(): time.asctime()을 간단하게 time.ctime()으로 표현할 수 있다. 차이점 현재 시간만 리턴
d = time.ctime()
print(d)

# time.strftime(): time.strftime('출력할 형식 포멧 코드', time.localtime(time.time()))
# 형식으로 사용
"""
시간에 관계된 포맷 코드
포맷코드        설명                 예
%a         요일 줄임말             Mon
%A         요일                   Monday
%b         달 줄임말               Jan
%B         달                    January
%c         날짜와 시간을 출력       08/02/21 10:49:21
%d         날(day)                [01, 31]
%H         시간-24시간             [00, 23]
%I         시간-12시간             [01, 12]
%j         1년 중 누적날짜          [001, 366]
%m         달                     [1, 12]
%M         분                     [01, 59]
%p         AM PM                  AM
%S         초                     [00, 59]
%U         1년 누적 주(일 시작)      [00, 53]
%w         숫자로 된 요일            [0(일요일), 6]
%W         1년 누적 주(월 시작)      [00, 53]
%x         로케일 기반 날짜 출력      06/01/01
%X         로케일 기반 시간 출력      10:57:10
%Y         년도 출력                2021
%Z         시간대 출력              대한민국 표준시
%%         문자                    %
%y         2자리 연도 출력           21
"""

e = time.strftime('%x', time.localtime(time.time()))
print(e)
f = time.strftime('%c', time.localtime(time.time()))
print(f)

# time.sleep(): 일정한 시간 간격을 준다.
for i in range(10):
    print(i)
    time.sleep(1)

# calendar: 달력을 볼 수 있게 해주는 모듈
# calendar.calendar(연도) 그 해의 전체 달력을 볼 수 있다.
import calendar

print(calendar.calendar(2021))
print(calendar.prcal(2021))  # calendar.calendar(2021) 같은 결괏값 출력
print(calendar.prmonth(2021, 8))  # 해당 연도, 해당 달만 출력
print(calendar.weekday(2021, 8, 2))  # 요일 리턴 0~6까지 출력
# (0: 월, 1: 화, 2: 수 , 3: 목, 4: 금, 5: 토, 6: 일)
print(calendar.monthrange(2021, 8))  # 2021년 8월 1일이 일요일이고 31일까지 있다.

# random: 임의의 수 (난수)를 발생시키는 모듈
import random

a = random.random()  # 0.0~1.0 사이의 실수 값을 랜덤하게 리턴
print(a)
print(random.randint(1, 10))  # 1 ~ 10 사이의 정수 값 중 랜덤한 값 리턴
print(random.randint(1, 55))  # 1 ~ 55 사이의 정수 값 중 랜덤한 값 리턴


def random_pop(data):
    number = random.randint(0, len(data) - 1)
    return data.pop(number)  # pop()을 이용해 값을 추출하고 삭제


if __name__ == "__main__":
    data = [1, 2, 3, 4, 5]
    while data:
        print(random_pop(data))

# 리스트 항목을 무작위로 섞고 싶을 때는 random.shuffle() 함수를 사용
import random

data = [1, 2, 3, 4, 5]
random.shuffle(data)
print(data)

# webbrowser: 자신의 시스템에서 사용하는 기본 브라우저를 자동으로 실행하는 모듈
import webbrowser

webbrowser.open("http://google.com")

# thread
import time
import threading


def long_task():
    for i in range(5):
        time.sleep(1)
        print("working:%s\n" % i)


"""
print("start")
for i in range(5):
    long_task()
print("end")  # 5 * 5 = 25초의 시간이 걸린다. 쓰레드를 사용하면 시간을 줄일 수 있다.
"""

print("start")
threads = []
for i in range(5):
    t = threading.Thread(target=long_task)
    threads.append(t)
for t in threads:
    t.start()
for t in threads:
    t.join()  # thread가 종료될 때까지 기다리게 한다.
print("end")

 

정규식

정규표현식 또는 정규식(regular expression)은 복잡한 문자열을 처리할 때 사용하는 기법이다. 특정 문자열을 포함하는문자열을 추출 또는 검색하기 위해 사용한다.

# 정규표현식(Reqular Expressions)
# 메타 문자(meta characters): 원래 그 문자가 가진 뜻이 아닌 특별한 용도로 사용하는 문자
"""
. ^ $ * + ? { } [ ] \ | ( )
"""

# 문자 클래스 []: 문자 클래스를 만드는 메타 문자인 [] 사이에는 어떤 문자도 들어갈 수 있다.
# 정규 표현식 [abc]라면 이 표현식의 의미는 "a, b, c 중 한 개의 문자와 매치"를 뜻한다.
# "a", "before", "dude"가 정규식 [abc]와 어떻게 매치되는지 살펴보면,
"""
a: 정규식과 일치하는 문자인 "a"가 있으므로 매치
before: 정규식과 일치하는 문자인 "b"가 있으므로 매치
dude: 정규식과 일치하는 문자인 a, b, c 중 어느 하나도 포함하고 있지 않으므로 매치되지 않음
"""

# [] 안의 두 문자 사이에 하이픈(-)을 사용하면 두 문자 사이의 범위 (From - To)를 의미한다.
"""
예: [a-c]라는 정규식 표현은 [abc]와 동일하고 [0-5]는 [012345]와 동일하다.
[a-zA-A]: 알파벳 모두, [0-9]: 숫자
^: not을 의미, 예를 들어 [^0-9] 숫자가 아닌 문자만 매치
[자주 사용하는 문자 클래스] 별도 표기법, 대문자는 소문자의 반대
\d: 숫자와 매치, [0-9]와 동일
\D: 숫자가 아닌 것과 매치, [^0-9]
\s: whitespace 문자와 매치, [ \t\n\r\f\v]와 동일한 표현식, 맨 앞의 빈칸은 공백문자(space)를 의미
\S: whitesapce 문자가 아닌 것과 매치 [^ \t\n\r\f\v]와 동일한 표현식
\w: 문자 + 숫자와 매치 , [a-zA-Z0-9]와 동일
\W: 문자 + 숫자가 아닌 문자와 매치, [^a-zA-Z0-9]와 동일
"""

# Dot(.): Dot 메타 문자는 줄바꿈 문자인 \n을 제외한 모든 문자와 매치됨을 의미.
"""
a.b: "a + 모든문자 + b" a와 b 문자 사이에 어떤 문자가 들어가도 모두 매치된다는 의미.
"aab", "a0b", "abc" 가 정규식 a.b와 매치되는지 살펴보면,
"aab": a + a + b 가 모든 문자를 의미하는 .과 일치하므로 정규식과 매치
"a0b": a + 0 + b 이름로 정규식과 매치
"abc": a + b + c, a와 b 사이에 문자가 없으므로 매치되지 않는다.
"""

# a[.]b: "a + Dot(.)문자 + b" , a.b 문자열과 매치되고, a0b 문자열과는 매치 되지 않는다.
# 이때의 의미는 모든 문자가 아니고 [.]은 '.'문자 자체을 의미.
# 반복 (*): ca*t -> '*'은 '*' 바로 앞에 있는 문자 a가 0부터 무한대로 반복될 수 있다는 의미.
# '*' 메타문자는 반복 개수가 무한대하고 표현했지만, 메모리 제한으로 2억 개 정도만 가능.
# 아래와 같은 문자열이 모두 매치된다.
"""
    정규식         문자열         Match여부         설명
    ca*t        ct              Yes             "a"가 0번 반복되어 매치
    ca*t        cat             Yes             "a"가 0번 이상 반복되어 매치(1번 반복)
    ca*t        caaat           Yes             "a"가 0번 이상 반복되어 매치(3번 반복)
"""

# 반복 (+): 최소 1번 이상 반복될 때 사용한다. '*'은 0부터, '+'은 1부터
# ca+t -> "c + a(1번 이상 반복) + t"
"""
    정규식       문자열           Match여부        설명
    ca+t        ct              No              "a"가 0번 반복되어 매치되지 않음
    ca+t        cat             Yes             "a"가 0번 이상 반복되어 매치(1번 반복)
    ca+t        caaat           Yes             "a"가 0번 이상 반복되어 매치(3번 반복)
"""

# 반복 ({m, n}, ?): 반복 횟수를 고정시킬 수 있다.
"""
1. {m}
    ca{2}t: "c + a(반드시 2번 반복) + t" -> caat 만 매치
2.{m, n}
    ca{2, 5}t: "c + a(2~5회 반복) + t" -> caat, caaaaat 매치
3. ?
    ab?c: "a + b(있어도 되고 없어도 된다) + c"
    abc 매치, "b"가 1번 사용되어 매치, ac "b"가 0번 사용되어 매치
"""

# 파이썬은 정규 표현식 re(reqular expression)모듈을 제공, 파이썬 설치 시 자동으로 설치됨.
import re

p = re.compile('ab*')  # re.compile()을 사용하여 정규 표현식 (ab*)을 컴파일했다.

# 컴파일된 패턴 객체를 사용하여 문자열 검색을 수행, 컴파일된 패턴 객체는 4가지 메서드 제공한다.
# 패턴은 정규식을 컴파일한 결과
"""
method      목적
match()     문자열의 처음부터 정규식과 매치되는지 조사
serach()    문자열 전체를 검색하거나 정규식과 매치되는지 조사
findall()   정규식과 매치되는 모든 몬자열을 리스트로 리턴
finditer()  정규식과 매치되는 모든 문자열을 반복 가능한 객체로 리턴
"""

# match(), search()는 정규식과 매치될 때는 match 객체를 돌려주고, 매치되지 않을 때는 None을 리턴
import re

p = re.compile('[a-z]+')

# match: 문자열의 처음부터 정규식과 매치되는지 조사
m = p.match("python")  # python 문자열은 [a-z] 정규식에 부합되므로 match 객체를 돌려준다.
print(m)
n = p.match("3 python")
print(n)  # None 리턴 숫자 3이 들어가서 부합되므로 None(거짓)을 리턴

# search(): 컴파일된 패턴 객체 p를 가지고 , search 메서드를 수행
m = p.search("python")
print(m)
m = p.search("3 python")  # "3 python"의 첫번째 문자는 3이지만 search는 문자열의 처음부터 검색하는
print(m)  # 것이 아니라 문자열 전체를 검색하기 때문에 "3 "이후의 "python" 문자열과 매치된다.

# findall(): life is too short 문자열의 'life' , 'is, 'too', 'short'
# 단어를 각각 [a-z]+정규식과 매치해서 리스트로 리턴
result = p.findall("Life is too short")
print(result)

# finditer(): Life is too short를 반복 가능한 객체로 리턴.
result = p.finditer("Life is too short")
print(result)
for r in result:
    print(r)

# match 객체의 메서드
# group(): 매치된 문자열을 리턴
# start(): 매치된 문자열의 시작 위치 리천
# end(): 매치된 문자열의 끝 위치 리턴
# span(): 매치된 문자열의 (시작, 끝)에 해당하는 튜플을 리턴.
m = p.match("python")
print(m.group())
print(m.start())
print(m.end())
print(m.span())

m = p.search("3 python")
print(m.group())
print(m.start())
print(m.end())
print(m.span())

# 컴파일 옵션
# DOTALL(S) - '.'이 줄바꿈 문자를 포함하여 모든 문자를 매치할 수 있도록 한다.
# IGNORECASE(I) - 대 소문자에 관계없이 매치할 수 있도록 한다.
# MULTILINE(M) - 여러줄과 매치할 수 있도록 한다. (^, $ 메타 문자의 사용과 관계가 있는 옵션)
# VERBOSE(X) - verbose 모드를 사용 할 수 있도록 한다.(정규식을 보기 편하게 만들고 주석 사용이 가능.)
# DOTALL, S
import re

p = re.compile('a.b', re.DOTALL)
m = p.match('a\nb')
print(m)

# IGNORECASE, I
p = re.compile('[a-z]', re.I)
p.match('python')
p.match('Python')
p.match('PYTHON')

# MULTILINE, M
import re

p = re.compile("^python\s\w+", re.MULTILINE)
data = """python one
life is too short
python two
you need python
python three"""
print(p.findall(data))

# VERBOSE, X
charref = re.compile(r'&[#](0[0-7]+[0-9]+|x[0-9a-fA-F]+);')  # 정규식
charref = re.compile(r"""
    &[#]    #start of a numeric entity reference
    (
        0[0-7]+ # Octal form
      | [0-9]+ # Decimal form
      | x[0-9a-fA-F]+ #hexadecimal form
)
;   # Trailling semicolon
""", re.VERBOSE)

 

numpy

numpy는 과학 계산을 위한 라이브러리로 다차원 배열을 처리하는 데 필요한 여러 가지 유용한 기능을 제공한다. 명령 프롬프트나 터미널(terminal)에 'pip install numpy'를 입력하여 numpy 라이브러리를 설치한다. 파이썬의 기본 자료형인 리스트를 numpy 배열로 만들어 배열 연산을 쉽게 해 준다.

# numpy
# numpy 배열(array)
# 배열의 차원을 rank라 하고, 각 차원의 크기를 튜플로 표시하는 것을
# shape라 한다. 예를 들어, 행이 2이고, 열이 3인 2차원 배열에서 랭크는 2, shape는 (2, 3)이다.
import numpy as np

list1 = [1, 2, 3, 4]
a = np.array(list1)
print(a.shape)  # (4,)
b = np.array([[1, 2, 3], [4, 5, 6]])
print(b.shape)  # (2, 3)
print(b[0, 0])  # 1

# numpy에서 제공하는 함수를 사용하여 numpy 배열을 만들어 보자.
# zeros(): 해당 배열에 모두 0을 대입
# ones(): 모두 1을 대입
# full(): 배열에 사용자가 지정한 값을 넣는 데 사용
# eye(): 대각선으로는 1, 나머지는 0인 2차원 배열을 생성
# 0 ~ n-1까지의 숫자를 생성하는 range(n) 함수와 배열을 다차원으로 변형하는 reshape()를 통해 배열을 생성
import numpy as np

a = np.zeros((2, 2))
print(a)
a = np.ones((2, 3))
print(a)
a = np.full((2, 3), 5)
print(a)
a = np.eye(3)
print(a)
a = np.array(range(20)).reshape((4, 5))
print(a)

# numpy 슬라이싱: 리스트와 마찬가지로 슬라이싱을 지원한다. numpy 배열을 슬라이싱하기 위해서는
# 각 차원별로 슬라이스 범위를 지정한다.
import numpy as np

list = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
arr = np.array(list)
a = arr[0:2, 0:2]  # slice
print(a)
a = arr[1:, 1:]
print(a)

# numpy 정수 인덱싱(integer indexing): 각 차원별로 선택되는 배열 요소의 인덱스들을 일렬로
# 나열하여 부분집합을 구하는 방식. 임의의 numpy 배열 a에 대해 a[[row1, row2], [col1, col2]]와
# 같이 표현, 이는 a[row1, col1], a[row2, col2]라는 두 개의 배열 요소의 집합을 의미한다.
# a[[0, 2], [1, 3]] -> a[0, 1], a[2, 3]
import numpy as np

list = [[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]]
a = np.array(list)
# 정수 인덱싱
s = a[[0, 2], [1, 3]]  # a [0,1], a[2,3] 주의..
print(s)

# numpy 불린 인덱싱(boolean indexing): 배열 각 요소의 선택 여부를 True, False로 표현하는 방식
# 만약 배열 a가 2 X 3 의 배열이라면, 불린 인덱싱을 정의하는 numpy 배열도 2 X 3 으로 만들고 선택 요소에
# True를 넣고 그렇지 않으면 False를 넣는다.
# 3 X 3 배열 a 중 짝수만 뽑아내는 불린 인덱싱 배열(numpy 배열)을 사용하여 짝수 배열 n을 만드는 예
import numpy as np

list = [[1, 2, 3],
        [4, 5, 6],
        [7, 8, 9]]
a = np.array(list)
bool_indexing_array = np.array([
    [False, True, False],
    [True, False, True],
    [False, True, False]
])

n = a[bool_indexing_array]
print(n)

import numpy as np

list = [[1, 2, 3],
        [4, 5, 6],
        [7, 8, 9]]
a = np.array(list)
bool_index = (a % 2 == 0)  # 짝수 = True, 홀수 = False
print(bool_index)
# 출력: 불린 인덱스 배열
# [False, True, False]
# [True, False, True]
# [False, True, False]

print(a[bool_index])  # 불린 인덱스를 사용하여 True인 요소만 뽑아냄

n = a[a % 2 == 0]
print(n)

# numpy 연산, 배열 간의 연산  +, -, * ,/ 등의 연산자 사용, add(), subtract(), multiply(),
# divide() 등의 함수를 사용할 수 있다. 배열 a와 b가 있을 때, a + b를 하면 배열 요소의 합을
# 구하는데, a[0]+b[0], a[1] +a[1]과 같은 형식으로 결괏값을 리턴.
import numpy as np

a = np.array([1, 2, 3])
b = np.array([4, 5, 6])
# c = a + b
c = np.add(a, b)
print(c)
# c = a - b
c = np.subtract(a, b)
print(c)
# c = a * b
c = np.multiply(a, b)
print(c)
# c = a / b
c = np.divide(a, b)
print(c)

# numpy에서 vector와 martix의 product를 구하기 위해 dot() 함수(행렬곱)를 사용한다.
import numpy as np

list1 = [[1, 2], [3, 4]]  # ((0,0 * 1,0)+(0, 1 * 1,0),(0,0 * 1,1)+(0, 1 * 1,1))
list2 = [[5, 6], [7, 8]]  # ((1,0 * 1,0)+(1, 1 * 1,0),(1,0 * 1,1)+(1, 1 * 1,1))
a = np.array(list1)
b = np.array(list2)
c = np.dot(a, b)
print(c)
# (1*5+2*7)(1*6+2*8) = (19,22)
# (3*5+4*7)(3*6+4*8) = (43,50)

import numpy as np

a = np.array([[1, 2], [3, 4]])
s = np.sum(a)  # 행렬의 모든 요소를 더하라
print(s)  # 10
s = np.sum(a, axis=0)  # axis = 축, 0 칼럼끼리 더함
print(s)  # 4, 6
s = np.sum(a, axis=1)  # axis = 1 로우끼리 더함
print(s)  # 3 ,7
s = np.prod(a)  # 배열의 각 요소를 모두 곱한 값을 리턴
print(s)  # 24