회문은 유전자 염기서열 분석에서 많이 쓰고, N-gram은 빅 데이터 분석, 검색 엔진에서 많이 쓰인다.
회문(palindrome)은 순서를 거꾸로 읽어도 제대로 읽은 것과 같은 단어와 문장을 말한다. ex) "level", "SOS", "rotator", "nurses run"
회문 판별하기 : 회문은 첫 번째 글자와 마지막 글자가 같다. 그리고 안쪽으로 한 글자씩 좁혔을 때 글자가 서로 같으면 회문이다.
word = input('단어를 입력하세요: ')
is_palindrome = True # 회문 판별값을 저장할 변수, 초깃값은 True
for i in range(len(word) // 2): # 0부터 문자열 길이의 절반만큼 반복
#첫번째, 마지막 문자열 비교를 위한 if문
if word[i] != word[-1 - i]: # 왼쪽 문자와 오른쪽 문자를 비교하여 문자가 다르면
is_palindrome = False # 회문이 아님
break
print(is_palindrome) # 회문 판별값 출력
#회문이면 True아니면 False 반환
word = input('단어를 입력하세요: ')
print(word == word[::-1]) # 원래 문자열과 반대로 뒤집은 문자열을 비교
word[::-1]은 문자열 전체에서 인덱스를 1씩 감소시키면서 요소를 가져오므로 문자열을 반대로 뒤집는다.
>>> word = 'level'
>>> list(word) == list(reversed(word))
True
>>> word = 'level'
>>> word == ''.join(reversed(word))
True
문자열을 뒤집고 join으로 공백없이('')연결한다. 위 두 방법과 동일하다.
N-gram은 문자열에서 N개의 연속된 요소를 추출하는 방법이다. 'Hello'라는 문자열을 문자(글자) 단위 2-gram으로 추출하면 다음과 같다.
He
el
ll
lo
text = 'Hello'
for i in range(len(text) - 1): # 2-gram이므로 문자열의 끝에서 한 글자 앞까지만 반복함
# Hello 01234 중 인덱스 3까지만 반복
print(text[i], text[i + 1], sep='') # 현재 문자와 그다음 문자 공백 없이 출력
3-gram이라면 반복 횟수는 range(len(text) - 2))와 같이 되고, 문자열 끝에서 두 글자 앞까지 반복하면 된다. 문자열을 출력할 때는 print(text[i], text[i + 1], text[i + 2], sep='')가 된다.
text = 'this is python script'
words = text.split() # 공백을 기준으로 문자열을 분리하여 리스트로 만듦
for i in range(len(words) - 1): # 2-gram이므로 리스트의 마지막에서 요소 한 개 앞까지 반복
print(words[i], words[i + 1]) # 현재 문자열과 그다음 문자열 출력
zip 함수는 반복 가능한 객체의 각 요소를 튜플로 묶어준다.
```
text = 'hello'
two_gram = zip(text, text[1:])
for i in two_gram:
print(i[0], i[1], sep='')
```
zip(text, text[1:])은 문자열 text와 text[1:]의 각 요소를 묶어서 튜플로 만든다. text[1:]은 인덱스 1(두 번째 문자)부터 마지막 문자까지 가져온다. 따라서 text와 text[1:]을 zip으로 묶으면 문자 하나가 밀린 상태로 각 문자를 묶는다.
```
>>> text = 'hello'
>>> list(zip(text, text[1:]))
[('h', 'e'), ('e', 'l'), ('l', 'l'), ('l', 'o')]
```
이렇게 2-gram 리스트가 만들어진다. 이 리스트를 출력할 때는 for i in two_gram:와 같이 for로 반복하면서 print(i[0], i[1], sep='')로 튜플의 요소를 출력한다.
3-gram을 만들고 싶다면 zip(words, words[1:], words[2:])와 같이 word, word[1:], word[2:] 3개의 리스트를 넣으면 된다.
아래는 3-gram에 필요한 슬라이스다. [text[i:] for i in range(3)]처럼 for로 3번 반복하면서 text[i:]로 리스트를 생성했다. 여기서 for i in range(3)는 0, 1, 2까지 반복하므로 text[i:]는 text[0:], text[1:], text[2:]가 된다.
>>> text = 'hello'
>>> [text[i:] for i in range(3)]
['hello', 'ello', 'llo']
리스트 ['hello', 'ello', 'llo']를 zip에 넣는다.
>>> list(zip(['hello', 'ello', 'llo']))
[('hello',), ('ello',), ('llo',)]
3-gram이 아니다. zip은 반복 가능한 객체 여러 개를 콤마로 구분해서 넣어줘야 하는데 ['hello', 'ello', 'llo']은 요소가 3개 들어있는 리스트 1개이기 때문이다.
zip에 리스트의 각 요소를 콤마로 구분해서 넣어주려면 리스트 앞에 *를 붙여야 한다.
>>> list(zip(*['hello', 'ello', 'llo']))
[('h', 'e', 'l'), ('e', 'l', 'l'), ('l', 'l', 'o')]
리스트 표현식(comprehension)을 바로 zip에 넣어주려면 리스트 표현식 앞에 *를 붙이면 된다.
>>> list(zip(*[text[i:] for i in range(3)]))
[('h', 'e', 'l'), ('e', 'l', 'l'), ('l', 'l', 'o')]