코린이의 소소한 공부노트

데이터 타입, 연산자 (2) 문자열형 본문

Python

데이터 타입, 연산자 (2) 문자열형

무지맘 2021. 5. 7. 18:02

문자열형을 둘러보기 전에 OX퀴즈 두 문제를 내보겠다.

- 변수를 확인할 때 타입만 확인하는 방법은 없다.

- 변수를 선언함과 동시에 반드시 값을 할당해줘야 한다.

 

(학교에서 시험 볼 때를 생각해보면, 답을 잘 모르겠을 때 '~만' 또는 '반드시'가 들어간 보기는 틀린 보기라는 게 너무 티가 나네ㅋㅋ 했었는데.. 막상 내가 내보니 그렇게 되는구나..ㅎ)

 

답은 X, X이다!

 

- 변수나 값의 타입이 궁금하다면 type함수를 쓰자.

a = 1.1
type(a)
>> float

type(1)
>> int

위에서 보듯 변수의 타입을 물어볼 수도 있고, 직접 값을 넣어 해당 값의 타입도 알 수 있다.

 

- 변수를 선언할 때 어떤 값을 할당해줘야 할지 아직 모르겠을 때, 혹은 변수 선언만 해놓고 나중에 값을 할당하고 싶을 때는 None을 쓰자.

not_yet = None
print(type(not_yet))
>> <class 'NoneType'>

print(not_yet)
>> None

not_yet에 None을 할당하니 NoneType이라고 나온다. (클래스는 차차 알아가보자.) 변수 선언 시 아무것도 넣지 않아서 아무것도 아닌 타입이라는 타입(?)이 된 것이다. 출력해봐도 None으로만 나온다. 

 

타입에 대한 소소한 궁금증도 풀어봤으니, 숫자형, 논리형 데이터에 이어 문자열형에 대해 알아보겠다.

문자열부터는 내용이 많아서 글 하나에 한 타입만 소개하려 한다.

이번 글에서 알아볼 것은

1. 문자열형을 선언하는 방법

2. 특별한 문자열, 이스케이프 문자

3. 문자열에 번호가 있다?!

4. 문자열 연산이다.


1. 문자열형(String type) 선언


문자열은 말 그대로 문자들의 나열(조합)이다.

문자열이 아무것도 들어있지 않은 빈 문자열은 이렇게 나타낸다.

empty_str = ''
print(empty_str)
>> ''

문자열이 들어있는 일반적인 문자열은 이렇게 쓴다.

str_example1 = 'Mom said, "Call me."'
str_example2 = "Life's so cool!"
print(str_example1)
>> Mom said, "Call me."

print(str_example2)
>> Life's so cool!

작은따옴표, 큰 따옴표 상관없이 써도 무방하다.(당연히 짝은 맞춰서 써야지, 작은 거랑 큰 거랑 섞어서 쓰면 안 된다!)

단, 문자열 안에 작은따옴표를 쓰고 싶다면 큰 따옴표로 문자열을 감싸고, 큰 따옴표를 쓰고 싶다 작은따옴표로 감싸야 에러가 발생하지 않는다.

str_example3 = '''여러 줄로도
가능합니다
'''
str_example4 = """
이것도
가능하지요!"""
print(str_example3)
>> 여러 줄로도
가능합니다
               # 이 줄은 print의 결과!!
               # 이 줄은 가독성을 위해 띄워둔 줄!
print(str_example4)
>>
이것도
가능하지요!

따옴표를 3개씩 겹쳐서 문자열을 감싸면 여러 줄로도 출력이 가능하다.

눈치를 챈 사람도 있겠지만, 따옴표를 문자열과 같은 줄에 쓰냐 다른 줄에 쓰냐에 따라서 엔터가 한 번 들어가는지 안 들어가는지도 차이가 있다.


2. 특별한 문자열, 이스케이프 문자(escape string)


문자열 선언을 보다 보면 이런 생각이 들 수 있다.

여러 줄을 쓰는 건 꼭 따옴표 3개로만 표현이 가능한 것인가? 답은 아니다!

이스케이프 문자(escape string)는 문자들 중에서 일부를 특정한 의미로 쓸 수 있게 만든 문자열이다.

이스케이프는 \(백슬래쉬 또는 원화)를 써서 문자에 의미를 부여해서 쓴다.

\n 엔터(줄바꿈) \t \b 백스페이스 \000 널(null)
\\ \ 자체 \' 작은따옴표 \" 큰따옴표    
\r 줄바꿈+커서 앞으로 이동 \f 줄바꿈+커서 다음으로 이동 \a 벨소리 \v 수직탭

색이 연한 것은 잘 안 쓰이는 거라고 들었다. 본인은 \n밖에 안 써봤기 때문에 나머지 이스케이프 문자들이 어떻게 나오나 궁금해서 한번 돌려보기로 했다.

print('python') # 일반 출력
>> python

print('\npython') # 줄바꿈(\n)
>>
python

print('\tpython') # 탭(\t)
>> 	python

print('python\b') # 백스페이스(\b)
>> pytho

일반 출력을 기준으로 보면 줄 바꿈은 한 줄 띄기, 탭은 한탭 띄기, 백스페이스는 \b 앞 문자 1개를 지우기를 하고 있음을 알 수 있다.

print('\000') # 널(\000)
>>

print('싸이버거 \\3,800') # \자체(\\), 글씨체에 따라 백슬래쉬 또는 원화로 나올것이다.
>> 싸이버거 \3,800

print('mom\'s touch') # 작은따옴표(\')
>> mom's touch

print('큰따옴표는 \"이거야!') # 큰따옴표(\")
>> 큰따옴표는 "이거야!

널(null)은 아무것도 들어있지 않은 빈 문자열이다. 출력해도 아무것도 안 나온다.

문자열에 원화표시 또는 백슬래쉬를 그대로 출력하고 싶을 때는 두 번 쓰면 된다.

처음에 문자열 선언 시 문자열 안에 ' 또는 "을 쓰고 싶으면 반대되는 따옴표로 문자열을 감싼다고 하면 된다고 했는데, 이렇게 이스케이프 문자를 이용해서도 사용 가능하다.

 

연한 색으로 나타낸 것들은 포스팅 안 하려다가, 갑자기 궁금해져서 막 찾아봤다.

\r(줄바꿈+커서 앞으로 이동)의 경우, 출력할 때 같은 줄에 계속 덮어쓰기를 하고 싶을 때 사용한다고 한다. 파일 복붙 할 때 이름이 같을 때 덮어쓰기 기능과 유사한 듯하다.

a = '안녕하세요'
b = '반갑습니다'
print(a, b)
>> 안녕하세요 반갑습니다

print(a, '\r', b)
>>  반갑습니다

첫 print문에서는 '안녕하세요'와 '반갑습니다'가 같이 출력됐는데, 중간에 \r을 넣었더니 '안녕하세요'는 덮어써져서 없어지고 '반갑습니다'만 출력된다. print에서는 기본 sep가 띄어쓰기로 되어있어서 두 번째 print문 출력 시 띄어쓰기하고 반갑습니다가 출력된다.

같은 내용을 \f(줄바꿈+커서 다음으로 이동)을 이용해서 다시 한번 출력해보겠다.

print(a, b)
>> 안녕하세요 반갑습니다

print(a, '\f', b)
>> 안녕하세요  반갑습니다

커서가 맨 앞으로 가지 않고 다음칸으로 이동했기 때문에 안녕하세요 반갑습니다가 한 줄에 출력되었다. 세 변수가 한 print문에서 출력됐으니 안녕하세요와 반갑습니다 사이에는 sep가 두 번 들어가서 두 번째 출력이 첫 출력보다 띄어쓰기가 더 되어있는 것을 확인할 수 있다.

\a와 \v는 생략... 주피터 노트북에서 돌려보니까 이런 게 나와서..

[그림 002] 이건 왜 이렇게 나오는걸까?

이게 왜 벨소리이고 수직 탭을 나타내는 것이란 말이냐..ㅠㅠ 더 공부를 하다가 알게 되면 그때 이 글을 수정하도록 하겠다.

 


3. 문자열에 번호가 있다! 인덱스(index)


문자열은 문자가 나열된 것이다. 고로 앞에서부터 번호를 정할 수 있다. 그 번호를 인덱스라고 부르고, 인덱스를 이용해서 원하는 문자만 쏙쏙 뽑아낼 수 있다.

i_say = "무지는 사랑이야"
i_say[1] # 첫번째니까 '무'가 나오겠지?
>> '지'

인덱스는 0번째부터 시작하기 때문에, 제일 앞 글자를 가지고 오려면 0번을 불러야 한다.

그럼 마지막 글자를 가지고 오려면?? (문자열 길이-1)번째를 불러오면 된다.

print(len(i_say))
>> 8

print(i_say[7])
>> 야

len 함수는 변수의 길이를 출력해주는 함수이다. i_say의 길이가 8이므로 마지막 글자는 7번째가 된다.

인덱스에 대해 조금 더 설명할 것이 있다.

파이썬은 음수 인덱스를 지원한다. 왜냐고 투덜거리는 사람도 있을 것이다. (저요 저요..) 문자열의 길이를 모르는 상황에서 마지막 값이 필요할 때가 많았어서 생긴 게 아닐까 생각해봤다.

i_say의 길이는 8였다. 마지막 글자는 7번째이면서 -1번째다. 나머지도 살펴볼까?

문자열  
본 인덱스 0 1 2 3 4 5 6 7
음수인덱스 -8 -7 -6 -5 -4 -3 -2 -1

이렇게 보면 (본 인덱스) + (음수인덱스의 절댓값) = (문자열의 길이)라는 것을 알 수 있다.

인덱스를 이용한 코딩을 할 때, [0, 문자열의 길이) 또는 [-(문자열의 길이), -1] 범위의 인덱스만 유효하기 때문에, 이 범위를 벗어나면 에러가 발생한다. 수학에서 구간을 표시할 때 [ - 이상, ] - 이하, ( - 초과, ) - 미만으로 표시한다.

print(len(i_say))
>> 8

i_say[8]
>> IndexError: string index out of range

문자열의 길이를 꼭 확인해보고 코딩할 것을 권장한다!


4. 문자열 연산


문자열 연산은 많고많고많고많지만, (내가) 많이 쓰는 연산들만 소개하고, 차차 내공이 쌓여서 다른 것도 접하게 되면 조금씩 추가해 나갈 예정이다.

 

첫 번째, 문자열 잘라내기(slicing)이다.

a = '일이삼사오육칠팔구십'
print(len(a)) # a의 길이
>> 10

print(a[1:4]) # 1번 ~ 3번 출력
>> 이삼사

print(a[:6])  # 0번 ~ 5번 출력
>> 일이삼사오육

print(a[4:])  # 4번 ~ 끝까지 출력
>> 오육칠팔구십

print(a[:])   # 처음부터 끝까지 출력
>> 일이삼사오육칠팔구십

print(a)      # 변하지 않아요!
>> 일이삼사오육칠팔구십

[시작:끝]을 써놓으면 [시작, 끝)에 해당하는 문자열을 잘라내준다. 물론 a는 변하지 않는다.

시작 또는 끝을 명시하지 않으면 처음부터 또는 끝까지로 인식한다.

 

두 번째, upper와 lower이다. 모든 문자열을 대문자 / 소문자로 바꿔준다.

b = 'pengsoo'
print(b.upper()) # 대문자로 바꿔주는 함수
>> PENGSOO

print(b)         # 원래 변수는 변화 없음
>> pengsoo

b = b.upper()    # 대문자로 바꾼 것을 변수에 할당
print(b)
>> PENGSOO

print(b.lower()) # 소문자로 바꿔주는 함수
>> pengsoo

print(b)         # 역시 원래 변수는 변화 없음
>> PENGSOO

 

 

세 번째, replace이다. replace(a, b)를 쓰면 모든 a를 b로 바꿔준다.

c = '빅머니 가즈아 빅머니!!'
print(c.replace('빅', '스몰')) # 모든 빅을 스몰로 치환
>> 스몰머니 가즈아 스몰머니!!    # 너무 슬픈 말이군

print(c)                      # 문자열에 영향 안줌
>> 빅머니 가즈아 빅머니!!       # 다시 기뻐졌다.

 

네 번째, format이다. 값이 바뀌는 변수를 문자열에 넣고 싶을 때 쓴다.

lunch = '피자'
time = '오후 12시 30분'

# 약속을 정해서 톡 공지에 올렸다.
promise = '내일 {} 먹으러 가자! 시계탑에서 {}에 만나!'.format(lunch, time)
print(promise)
>> 내일 피자 먹으러 가자! 시계탑에서 오후 12시 30분에 만나!

# 다욧하는 무지맘이 애원했다.
lunch = '연어덮밥'

# 다들 다욧중이니 점심메뉴를 바꾸기로 했다.
promise = '내일 {} 먹으러 가자! 시계탑에서 {}에 만나!'.format(lunch, time)
print(promise)
>> 내일 연어덮밥 먹으러 가자! 시계탑에서 오후 12시 30분에 만나!

문자열 안에 {}을 이용해서 변숫값을 넣고 싶은 위치를 정한 다음. 문자열 뒤에 .format을 붙이고 앞에서부터 넣고 싶은 변수를 순서대로 입력하면 완성이다.

만약 두 번째 promise 선언을 하지 않았다면 점심메뉴는 그대로 피자다.. 다욧은 힘들어ㅠㅠ

 

마지막으로 볼 연산은 split이다. 특정 문자(정해주지 않으면 띄어쓰기)를 기준으로 문자열을 나눠서 리스트로 반환한다. (리스트는 데이터 타입, 연산자(3)에 설명되어있다.)

he_said = '나는.. 수줍음을 많이 타.. 어떻게 말을 하지..?'
she_said = '어떻게 하긴! 이렇게! 자신있게! 말하라고!'
print(he_said.split('..'))
>> ['나는', ' 수줍음을 많이 타', ' 어떻게 말을 하지', '?']

print(she_said.split('!'))
>> ['어떻게 하긴', ' 이렇게', ' 자신있게', ' 말하라고', '']

he_said는 ..을 기준으로 문자열이 나눠졌고, she_said는 !를 기준으로 문자열이 나눠진 것을 확인할 수 있다.

print(he_said)
>> 나는.. 수줍음을 많이 타.. 어떻게 말을 하지..?

print(she_said)
>> 어떻게 하긴! 이렇게! 자신있게! 말하라고!

물론 이것도 원래 변수에 영향을 주지 않는다.


<요약>

 

1. 문자열: 문자를 '작은따옴표', "큰따옴표"로 감싸기

2. 이스케이프 문자: 특별한 의미. \n, \t 등

3. 인덱스: 0번부터 시작하는 문자들의 위치

4. 문자열 연산

- slicing: 부분 추출

- upper, lower: 대/소문자 변환

- replace: 원하는 문자열로 교체

- format: 동적 문자열 생성

- split: 기준 문자로 문자열 나누기