여백으로 구분된 데이터 처리
다수 행 레코드
미리보기
정규표현식
\d > 숫자 [0-9]
\D > 숫자가 아닌 것. [^0-9]
\s > white space. [ \t\n\r\f\v]
스페이스, 탭(09), 줄바꿈(LF, 0A), 캐리지리턴(CR, 0D), 폼피드(0C), 수직 탭(0B)
\S > white space가 아닌 것. [^ \t\n\r\f\v]
\w > 문자+숫자. [a-zA-Z0-9]
\W > 문자+숫자가 아닌 문자. [^a-zA-Z0-9]
\\ > 역슬래쉬(\)
\( > 소괄호 열기(()
\) > 소괄호 닫기 ())
* > 앞의 표현식이 0회 이상 연속으로 반복되는 부분과 대응 > {0,}
+ > 앞의 표현식이 1회 이상 연속으로 반복되는 부분과 대응 > {1,}
? > 앞의 표현식이 0 또는 1회 등장하는 부분과 대응 > {0,1}
. > 개행 문자를 제외한 모든 단일문자와 대응 (어떤 글자가 있고 그 바로뒤에 선택한 문자가 옴)
() > 그룹핑
{n} 또는 {n,m} > 반복
정규표현식을 이용한 데이터 추출
아래와 같은 데이터에서 (저자, 년도) 정보를 추출
평생교육 실습 체험에 대한 내러티브 연구 (김진숙, 2012)
직업적 전문성과 직무의 탐구 (박지혜, 2003)
대학생의 평생교육 실습경험 탐색 (최희준, 2008)
\([A-Za-z가-힣]+, \d+\)
\( 와 \) ⇒ 이스케이프. () 정규식에 의미문자이므로
[A-Za-z가-힣] ⇒ [] 안에 있는 문자 중 하나가 나올 수 있다
A-Z ⇒ 대문자
a-z ⇒ 소문자
가-힣 ⇒ 한글
⇒ 1번 이상 반복
[A-Za-z가-힣]+ ⇒ 영문 또는 한글로 된 단어가 올 수 있다.
\d ⇒ 숫자. [0-9]와 같은 의미
\d+ ⇒ 한자리 이상의 숫자
re.match(pattern, string, flags=0) : 문자열 도입에서 패턴 찾기
>>> import re
>>> pattern = 'life'
>>> string = 'human life'
>>> re.match(pattern, string)
>>> re.match(pattern, string).group()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'NoneType' object has no attribute 'group'
>>> string = 'life of human'
>>> re.match(pattern, string).group() # 매치된 내용을 반환
'life'
re.search(pattern, string, flags=0) : 문자열 전체에서 패턴 찾기
>>> pattern = 'life'
>>> string = 'human life'
>>> re.search(pattern, string).group()
'life'
>>> string = 'life of human'
>>> re.search(pattern, string).group()
'life'
re.findall(pattern, string, flags=0) : 패턴을 모두 찾아 리스트로 반환
홍길동 : 700127-1821234, 010-2222-3333
아무개 : 800812-2123452, 010-4444-5555
테스터 : 900202-4222214, 010-6666-7777
>>> import re
>>> members = '''홍길동 : 700127-1821234, 010-2222-3333
... 아무개 : 800812-2123452, 010-4444-5555
... 테스터 : 900202-4222214, 010-6666-7777
... '''
>>> re.findall('\d{6}-\d{7}', members)
['700127-1821234', '800812-2123452', '900202-4222214']
re.sub(pattern, repl, string, coung=0, flags=0) : 문자열 바꾸기
>>> sentence = "By learning to interpret dog body language and mimic the pack behaviors your dog craves, you can say 'I love you' to your dog in the following ways. \n\nWe all know that a loved dog equals a happy dog, and dog love equals pure love (just check out the video evidence!)"
>>> print(sentence)
By learning to interpret dog body language and mimic the pack behaviors your dog craves, you can say 'I love you' to your
dog in the following ways.
⇐ 문자열 내에 포함된 개행문자로 인해 불필요한 개행(줄바꿈)이 발생
>>> sentence = re.sub('\n', ' ', sentence)
>>> print(sentence)
By learning to interpret dog body language and mimic the pack behaviors your dog craves, you can say 'I love you' to your
dog in the following ways. We all know that a loved dog equals a happy dog, and dog love equals pure love (just check out the video evidence!)
>>> sentence = re.sub('dog', 'cat', sentence)
>>> print(sentence)
By learning to interpret cat body language and mimic the pack behaviors your cat craves, you can say 'I love you' to your
cat in the following ways. We all know that a loved cat equals a happy cat, and cat love equals pure love (just check out the video evidence!)
해쉬(Hash) = Message Digest
임의 크기의 데이터를 고정된 길이의 유일한 값으로 출력
충돌회피, 빠른연산 > 좋은 해쉬 알고리즘
- 유일성 a<>b —> H(a) <> H(b) 무결성 보장/검사
(데이터를 보낼 때 해쉬까지 같이 보내서 검증하여 동일한지 판단.)
- 일방향성 a → (o) → H(a) → (x) → a 반대 개념은 양방향 암호화
인증 정보를 저장하고, 인증을 처리
주민번호, 생체정보
양방향은 암호정보를 제3자에게 탈취 당할 수도 있음
해쉬를 크래킹하는 방법
H(pw) == H(????) ⇒ pw == ???
- 사전대입공격
- 무작위대입공격
- 레인보우테이블
해쉬 크래킹을 방어기법 ⇒ 입력값의 길이, 복잡도를 올림
- 숫자 10 자리로 구성된 해쉬 → 10 ^ 10
- 숫자, 영문자, 특수문자로 구성된 10자리 → (10 + 26 * 2 + 13) ^ 10
- 숫자, 영문자, 특수문자로 구성된 40자리 → (10 + 26 * 2 + 13) ^ 40
사용자가 10자정도만 입력하면 시스템이 알아서 뒤에더함 > salt
set 연산
기존
birds = []
with open('bird_data.txt', 'r') as file:
for line in file:
bird = line.strip()
if bird in birds:
continue
else:
birds.append(bird)
print(birds)
# 실행결과
# ['aaa', 'bbb', 'ccc', 'xxx', 'ddd']
set으로
birds = set()
with open('bird_data.txt', 'r') as file:
for line in file:
bird = line.strip()
birds.add(bird)
print(birds)
# 실행결과
# {'bbb', 'ddd', 'xxx', 'ccc', 'aaa'} (순서는 랜덤으로 나옴)
새의 종류 별로 관찰된 횟수를 출력 (리스트 이용)
새의 종류 별로 관찰된 횟수를 출력 (딕셔너리 이용)
aaa 3
bbb 4
ccc 4
xxx 2
ddd 1
훨씬 단순해졌다.
기존 데이터의 키와 값의 역할을 변경 → 충돌이 발생해서 값이 생략될 수 있음 —> 리스트와 같은 컬렉션을 이용해서 값을 저장해야 함
1 ddd
2 xxx
3 aaa
4 bbb ccc
알고리즘
가장 작은 두 값 찾기
from typing import List, Tuple, Any, Callable
import time
# 방법1. 찾고 삭제하고 찾기
def method_1(L: List[float]) -> Tuple[int, int]:
# L에서 가장 작은 항목을 구한다.
# 가장 작은 항목의 인덱스를 구한다.
# 리스트에서 그 항목을 삭제한다.
smallest = min(L)
min1 = L.index(smallest) # 첫번째 가장 작은 수의 인덱스
L.remove(smallest)
# 리스트에서 다음으로 가장 작은 항목의 인덱스를 구한다.
next_smallest = min(L)
min2 = L.index(next_smallest) # 두번째 가장 작은 수의 인덱스
# 가장 작은 항목을 리스트에 다시 넣는다.
L.insert(min1, smallest)
# 필요에 따라 두 번째 인덱스를 조정한다.
if min1 <= min2:
min2 += 1
# 두 인덱스를 반환한다.
return (min1, min2)
# 방법2. 정렬해서 최소값을 찾은 후 인덱스 구하기
def method_2(L: List[float]) -> Tuple[int, int]:
# L의 복사본을 정렬한다.
sorted_list = sorted(L)
# 가장 작은 두 수를 구한다.
smallest = sorted_list[0]
next_smallest = sorted_list[1]
# 원래 리스트 L에서 두 수의 인덱스를 구한다.
min1 = L.index(smallest)
min2 = L.index(next_smallest)
# 두 인덱스를 반환한다.
return (min1, min2)
# 방법3. 리스트 전체 훑기
def method_3(L: List[float]) -> Tuple[int, int]:
# L의 맨 앞부분에서 가장 작은 값과 두 번째로 작은 값의 인덱스를 min1과 min2에 할당한다.
if L[0] < L[1]:
min1, min2 = 0, 1
else:
min1, min2 = 1, 0
# 리스트 내 각 값을 순서대로 확인한다.
# 더 작은 값을 찾으면 인덱스를 업데이트한다.
for i in range(2, len(L)):
if L[i] < L[min1]:
min1, min2 = i, min1
elif L[i] < L[min2]:
min2 = i
# 두 인덱스를 반환한다.
return (min1, min2)
함수 시간 측정
# 함수의 실행 시간을 반환하는 함수
def func_runtime(find_func: Callable[[List[float]], Any], lst: List[float]) -> float:
t1 = time.perf_counter()
find_func(lst)
t2 = time.perf_counter()
return (t2 - t1) * 1000.0
items = [809, 834, 477, 478, 307, 122, 96, 102, 324, 476]
t1 = func_runtime(method_1, items)
t2 = func_runtime(method_2, items)
t3 = func_runtime(method_3, items)
print(t1)
print(t2)
print(t3)
파이썬 컬렉션
컬렉션 | 변경가능여부 | 정렬여부 | 사용하는경우 |
---|---|---|---|
str | X | O | 텍스트 저장할 때 |
list | O | O | 업데이트 시 정렬된 순서대로 저장하고 싶을때 |
tuple | X | O | 변경하지 않을걸 알고 정렬된 시퀀스를 만들고 싶을때, 딕셔너리의키나 세트의 값으로 사용 |
set | O | X | 순서가 중요하지 않을 때, 중복은 허용 안할때, 값은 불변 |
dictionary | O | X | 키/값 매핑을 저장하고 싶을 때, 키는 불변 |