▼2020년/파이썬 기초

[Python] 파이썬에서의 자료형, 문자형 (2/7)

ITISIK 2020. 1. 21. 14:38
반응형

  들어가기 전에... 글이 많이 깁니다. 내용은 많지만, 문자형은 데이터 분석에서 가장 많이 사용되고 능숙하게 다루어야하는 자료형이니만큼 꼼꼼하게 공부할 필요가 있다고 생각합니다. 한 번 훑어본 것으로 만족하지 마시고, 완전히 체화될 때까지 반복 숙달해주세요.

  이전 포스트에서는 숫자형 자료들에 대해서 배우고, 그 연산을 알아보았다면 이번 포스트에서는 문자형 자료들에 대해서 배우고 그 연산 뿐만 아니라 다양한 기능과 함수들을 배워보고자 한다.

문자형

  파이썬 이전의 프로그래밍 언어에서는 '문자'와 '문자열'을 구분지어 알아야 했다. 문자는 한 글자 한 글자를 의미하고, 문자열은 문자들을 나열한 것을 의미한 것이다. 예를들면 'L'은 문자이고 'LOVE'는 문자열인 셈이다. 하지만 파이썬에서는 굳이 구분지어 이해하지 않고 문자라는 개념만 가지고 있어도 학습에 큰 지장이 없다.

  문자형은 달랑 숫자만 적었던 숫자형과는 달리 작은따옴표나 큰따옴표로 묶어서 표현한다.

text1 = "alpha"
text2 = 'beta'

  위와 같이 문자열 alpha나 beta를 표현할 때 작은따옴표와 큰따옴표를 감쌈으로써 문자형 자료를 만들 수 있다. 혹은 아래와 같이 이들 기호를 세 개 연속 사용해서 나타낼 수도 있다.

text3 = """one"""
text4 = '''two'''

  겨우 문자형이라는 자료형 하나를 표현하는데 방법이 네 가지나 된다는게 비효율적으로 보이지 않는가? 다음의 예제들을 보면서 왜 이렇게 많은 표현 방법들이 생기게 되었는지 느껴보자.

  만약 내가 작성하려는 문자열 안에 인용부호(')가 들어가야하면 어떻게 해야할까?

keynote1 = 'He said, 'I LOVE YOU''

  보이다시피 구문오류(문법오류)를 내게 된다. 문자열 안에 작은따옴표를 사용하고 싶다면, 아래와 같이 감싸는 기호를 큰따옴표를 사용하면 된다.

keynote1 = "He said, 'I LOVE YOU'"

  그러면 반대로 큰따옴표를 사용하고 싶을 때에는? 맞다. 아래와 같이 작은 따옴표로 감싸주면 된다.

keynote2 = 'He said, "I LOVE YOU"'

  그런데 꼭 이런 방법으로만 사용해야할까? 그렇지 않다. 문자열 중에 작은따옴표(')나 큰따옴표(")를 사용하고 싶은 경우에는 아래와 같이 이스케이프 문자(\)에 해당하는 백슬래쉬(혹은 원화)를 이용해서 할당할 수 있다.

keynote3 = "He said, \"I LOVE YOU\""
keynote4 = 'He said, \'I LOVE YOU\''

  그러면 만약 여러줄에 걸쳐서 문자열을 작성하고 싶을 때에는 어떻게 해야할까?

mention1 = "너무 졸립지만, 그럼에도 불구하고 공부를 열심히 하고있어.\n이렇게 열심히 하다보면 언젠가 좋은 결과가 나오게 될거야."

  이렇게 \n을 통해서 줄바꿈을 해주면 된다. 하지만 가독성이 좋지 못하다. 분명 줄바꿈을 했지만 뭔가 하지 않은 것 같기도 하고, 어디서 줄바꿈이 이루어진건지 한참 들여다 봐야한다. 그럴때 사용하는 것이 삼중 따옴표이다.

mention2 = """너무 졸립지만, 그럼에도 불구하고 공부를 열심히 하고있어.
이렇게 열심히 하다보면 언젠가 좋은 결과가 나오게 될거야."""
mention3 = '''너무 졸립지만, 그럼에도 불구하고 공부를 열심히 하고있어.
이렇게 열심히 하다보면 언젠가 좋은 결과가 나오게 될거야.'''

  이전에 사용했던 이스케이프 문자를 활용한 줄 바꿈보다 한결 더 가독성이 좋아진 것을 볼 수 있다. 이렇게 작성해낸 문자열들을 print()함수를 이용하여 출력하면 줄바꿈이 그대로 표현되어 나타나게 된다.

코드 설명
\n 줄 바꿈
\t 탭 간격
\\ 역슬래시(\)를 그대로 표현
\' 작은따옴표(')를 그대로 표현
\" 큰따옴표(")를 그대로 표현
\r 캐리지 리턴, 커서를 가장 앞으로 이동
\f 폼 피드, 커서를 다음 줄로 이동
\a 알람소리(삑!)를 냄
\b 백스페이스. 한 글자 지움
\000 널 문자

  널 문자(NULL)란, 아무것도 존재하지 않는 상태를 의미하는 프로그래밍 개념이다. 예를들어 공백( )은 한 칸이 비어있는 상태로 존재한다. 하지만, 널(null)의 경우에는 그 한 칸 조차도 존재하지 않는 완벽한 무(無)의 상태를 의미하는 것이다.

문자열 연산

  이전 포스트에서 숫자형 자료를 다룰 때 덧셈(+)과 곱셈(*)연산 했던 것을 떠올리면서 직관적으로 이해하면 쉽다. 문자열 간에도 덧셈과 곱셈연산이 가능한데, 그 결과값을 유추하면서 진행하면 좀 더 이해가 쉽고 암기가 간단할 것이다.

front = "앞에 있는 문자열과"
back = " 뒤에 있는 문자열"
front + back

  예상한대로 나왔는가? "앞에 있는 문자열과 뒤에 있는 문자열"이라고 나온다. 실제로 두 개의 각기 다른 문자열을 접목(합친)시킨 것 처럼 나온다는 의미이다. 문자형에서의 +연산은 이런 기능을 갖는다.

repeat_text = "내가 누군지 알아?"
repeat_text * 2

  예상한대로 나왔는가? "내가 누군지 알아?내가 누군지 알아?"라고 나온다. 이와같이 문자형에 대한 곱셈연산은 그 횟수만큼 해당 문자열을 반복시키는 기능이 있다.

  이런 기능을 어디에 쓴단 말이지? 라고 생각할 수 있는데, 흔히 프로그램을 돌릴 때 가장 윗단에 해당 프로그램에 대한 간단한 정보나 메타 데이터를 적어두는데, 이때 구분선으로 "=====" 등을 사용한다. 이럴 때에도 유용하게 사용할 수 있다. 예를들면 print("=" * 20) 과 같이 말이다.

문자열 인덱싱

  인덱싱을 한국어로 바꾸면 '색인 시키다'정도가 된다. 인덱싱의 예는 두 가지 정도를 들 수 있는데 첫 번째로는 국어사전 등의 사전이다. 사전의 옆면에 보면 사람이 특정 단어를 빠르게 찾을 수 있도록 'ㄱ', 'ㄴ', 'ㄷ', ... 혹은 'a', 'b', 'c', ...와 같이 표시되어 있는 것을 본적이 있을 것이다. 이러한 것을 색인이라고 말하며, 이런 색인 덕분에 우리는 특정 단어를 빠르게 찾을 수 있게 된다.

  또 다른 예로는 논문이나 보고서 등에서 사용되는 목차(Index)이다. 보통 논문 등에서 표지를 제외하고 맨 앞장을 보면, 해당 논문의 몇 페이지부터 어떤 내용이 나오는지에 대해서 간단하게 소제목과 페이지를 적어둔 목차가 있다. 마찬가지로 이러한 목차 덕분에 우리는 특정 주제를 빠르게 찾을 수 있게 된다.

  문자열에도 우리 눈에는 보이지 않지만 이러한 색인이 자동으로 되어있다.

       
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21

  여기서 일반적인 상식과 조금 차이가 나는 부분이 있는데, 첫번째 글자에게 부여된 숫자가 1이 아니라, 0이라는 점이다. 만약 처음 프로그래밍 언어를 배우는 분이라면, 많이 헷갈릴겁니다.

  아무튼, '데'라는 글자만 쏙 뽑으려면 어떻게 해야할까? 아래처럼 코드를 작성하면 된다.

will = "파이썬을 잘하면 데이터 분석이 편해질거야"
will[9]

  이렇게 대괄호 안에 '위치에 해당하는 번호'를 넣으면, 해당 문자가 나타나게 된다. 여기서 방금 전에 배운 문자열 연산을 진행하면 새로운 단어를 만들어낼 수도 있다.

will[10] + will[18]

  이러한 대괄호 안에는 양수 뿐만 아니라 음수도 올 수 있는데, 그 정의를 아는 것이 중요하다.

will[-9] + will[-20]

  이렇게 음수는 마치 맨 뒤 문자를 -1로 잡은 것처럼 색인되어 있는데 그 이유는, 0과 -0은 수학적으로 동일한 값이기 때문이다.

문자열 슬라이싱

  슬라이싱이란, 마치 햄을 적당한 두께로 썰어 내는 것처럼, 문자열의 특정 부분을 취하는 방법을 의미한다. 방법은 아래 코드와 같다.

ham = "햄은 너무 맛있어. 하지만 건강에는 좋지 않아."

  여기서 슬라이싱을 이용하여 "건강"이라는 단어를 뽑아내보자

ham[16:18]

  위 코드에서 ham[16:18]이 의미하는 바를 해석하면, ham이라는 문자형 변수에서 16번째 문자열부터 17번째 문자열까지를 뽑아내라는 의미이다. 처음에는 뒤의 숫자가 17이 아닌 18인 것이 어색하지만, 이것이 파이썬 문법이므로 적응하고 익숙해지는 방법밖에는 없다. 추출해내는 범위를 수학적으로 나타내면 아래와 같다.

text[a:b]

$$a\le text<b$$

  만약 맨 처음부터 특정 위치까지를 추출하고 싶다면, text[:b]와 같이 나타내면 되며, 특정 위치부터 맨 마지막 까지를 추출하고 싶다면, text[a:]와 같이 나타내면 된다. 또한 슬라이싱에서 범위 지정에 사용되는 a값과 b값에도 음수를 사용할 수 있다.

  끝으로, 한 번 할당된 문자열은 무슨 일이 있어도 수정이 불가능하다. 이 말이 처음에는 이해하기 가장 힘든 이야기 중에 하나인데, 사실 우리가 변수에 문자열을 할당하게 되면, 메모리 상의 특정 위치에 해당 문자열을 입력 시켜두게 된다. 만약 그렇게 할당된 메모리 공간의 주소가 0xab였다면, 0xab에 할당된 그 문자열은 무슨일이 있어도 변할 수 없게 된다. 대신 변수에 새로운 문자열을 재할당시키면 문자열이 바뀐것처럼 느껴지는데, 이는 기존에 할당된 0xab주소에 새로운 문자열이 들어간 것이 아니라, 0xff라는 전혀 다른 주소에 새로운 문자열이 들어간 것이다.

immutable_text1 = "한 번 할당된 문자열"

# 메모리 공간 어딘가에 저장되었을 "한 번 할당된 문자열"
# 해당 메모리 공간은 이제 수정이 불가능하다


immutable_text1 = "새로운 문자열을 재할당"

# 뭐야 바뀌는데요?
# 바뀐게 아니라, 아까 그 메모리 공간은 버리고
# 새로운 메모리 공간에 "새로운 문자열을 재할당"이 저장된 것.
# immutable_text1 변수만 본다면 바뀌었다는 말이 맞을지도.

  문자열은 한 번 할당된 이후 무슨 일이 있어도 수정이 불가능하다는 이야기를 코드로 확인하고 싶다면 아래 코드를 수행해보면 된다.

immutable_text2 = "무슨 소리인지 하나도 모르겠어"
immutable_text2[8]
# 하
immutable_text2[8] = "나"
# error

문자열 포맷팅

  form이란, (문서 따위의)서식을 의미하는 말이다. format도 구성방식, (문서 따위의)서식을 의미하는 말이다. 포맷팅이랑 이러한 서식을 설정하고 해당 서식에 따라 사용하는 것을 의미한다.

  예를들어

"나스닥 지수 : 9000 입니다."

"현재 서울의 기온은 0도 입니다."

  라는 알람이 3시간 뒤에

"나스닥 지수 : 9170 입니다."

"현재 서울의 기온은 -3도 입니다."

  라는 알람으로 제목이 변경 되었다고 가정해보자.

  매번 사용되는 앞 뒤의 문장은 자르고, 숫자 부분만 간편하게 바꿀 수 있으면 좋겠다는 생각이 드시는가? 그리고, 그렇게 틀은 정해져 있고 내부에 일부 내용만 변경하는 것을 가리켜 서식이라고 하지 않는가? 포맷팅이란 이런 상황에서 유용하게 사용할 수 있는 문법이다.

"나스닥 지수 : %d 입니다." % 9000

  위와같이 숫자가 들어갈 위치에 %d로써 표시를 해주고, 삽입될 숫자 9000은 맨 마지막에 %뒤에 적혀있는 형태이다. 여기서 %d를 문자열 포맷 코드라고 한다.

"나스닥 지수 : %s 입니다." % "구천"

  또, 숫자가 아닌 문자를 넣으려고 할 때에는 %d 대신에 %s를 사용하여 자리를 표시해주고, 삽입된 문자 "구천"은 마찬가지로 맨 마지막에 %뒤에 적어주는 형태이다. 그러면 매번 이렇게 % 뒤에 해당 값을 적어주어야 하는지 의문이 든다. 아래와 같이 변수로 할당해줄 수도 있다.

temp = 0 "현재 서울의 기온은 %d도 입니다." % temp

  만약 두 개 이상의 값을 넣으려면 어떻게 해야할까?

nasdaq = 9170
temp = -3
"나스닥 지수는 %d이고, 현재 서울의 기온은 %d도 입니다." %(nasdaq, temp)

  문자열 포맷 코드에는 아래와 같은 것들이 있다.

코드 설명
%s 문자열(String)
%c 문자(Character)
%d 정수(Integer)
%f 부동소수(Floating point)
%o 8진수(Octal)
%x 16진수(Hexadecimal)
%% '%'라는 문자

  포맷팅을 이용해서 공백을 만들어내고 문자열을 정렬 시킬 수 있다.

"%10s" % "반가워"
# " 반가워"

  위에서 10s란, 10칸을 만들어서 's'tring을 우측정렬하라는 의미가 된다. 칸은 10칸인데 문자열은 3칸이기 때문에 나머지 7칸은 왼편에 공백으로 남게 된다.

"%-10s재밌다" % "파이썬"
# "파이썬 재밌다"

  여기서 -10s란, 10칸을 만들어서 's'tring을 왼쪽정렬하라는 의미가 된다. 칸은 10칸인데 문자열은 6칸이기 때문에 나머지 4칸은 오른편에 공백으로 남게 된다. 혹시 "파이썬재밌다 "처럼 나올줄 알았던 사람은, %-10s가 지정된 영역이 재밌다의 앞 부분이라는 점에 주목해야 한다.

  아래와 같이 포맷팅을 이용해서 소수점의 표현 범위를 설정할 수 있다.

"%0.4f" % 3.141592653589793238462643383
# '3.4213'

"%10.4f" % 3.141592653589793238462643383
# ' 3.4213'

  소수점도 하나의 문자에 해당하므로, 아래의 코드에서 공백은 4칸이 된다.

  지금부터는 이전보다 깔끔한 방법으로 포맷팅을 사용하려고 한다. 바로 중괄호(braces)를 이용한 방법이다.           

"{} is one!".format(1)
"{} is {}!".format(1, "one")

"{0} is one!".format(1)
"{0} is one!".format(1, "one")
"{0} is {1}!".format(1, "one")
"{1} is {0}!".format(1, "one")
"{1} is {1}!".format(1, "one")

  맨 위 두 줄 처럼 중괄호 속에 아무것도 넣지 않고 적어넣은 순서대로 할당할 수도 있다. 하지만 비워두기보다 format() 메소드 안에 넣어줄 변수의 개수대로 인덱스 번호를 넣어주는 것이 코드의 명확성 면에서 더 좋다. 이렇게 인덱스를 넣어주는 방법 말고, 변수 명으로 할당해주는 방법도 있다.

number = 10
ten = "ten"
"{0} is {1}!".format(number, ten)

"{number} is {ten}!".format(number = 10, ten = "ten")

포맷팅으로 문자열 정렬하기

  이와같은 중괄호 표현식 포맷팅을 활용해서 문자를 정렬할 수 있다.

"{0:<10}".format("ITisik")
# 총 10칸이되 왼쪽정렬

"{0:>10}".format("ITisik")
# 총 10칸이되 오른쪽정렬

"{0:^10}".format("ITisik")
# 총 10칸이되 가운데정렬

  위의 코드에서 지정된 칸은 10칸이지만, 문자의 개수는 6개여서 남는 4개의 칸은 공백으로 채워지는 모습을 볼 수 있다. 이번엔 공백대신 다른 문자로 대체해보겠다.

"{0:~>10}".format("ITisik")
# ~~~~ITisik

"{0:~^10}".format("ITisik")
# ~~ITisik~~

  소수점이 필요한 수를 나타낼 때에도 포맷팅 방법이 가능하다. 위에서 배웠던 형태와 유사하다.

pi = 3.1415926
"{0:10.5f}".format(pi)
# " 3.14159"

문자열 관련 내장 함수

  문자열에서 특정 문자의 갯수를 세어주는 count()함수

name = "itisik"
name.count("i")

  문자열에서 특정 문자가 첫 번째로 나타나는 위치를 알려주는 find()함수

name = "itisik"
name.find("i")
# 0
name.find("a")
# -1

  문자열에서 특정 문자가 첫 번째로 나타나는 인덱스 값을 알려주는 index()함수

name = "itisik"
name.index("i")
# 0 name.index("a")
# error

  문자열에서 문자 하나하나 사이에 특정 문자를 삽입해주는 join()함수

",".join('text')
# t,e,x,t
# 마치 csv처럼 처리된다.

join()함수의 인수로 리스트나 튜플이 올 수도 있다.

  소문자 to 대문자 upper()함수와 대문자 to 소문자 lower()함수

small.upper()
# SMALL BIG.lower()
# big

  공백 지우기 3총사 lstrip(), rstrip(), strip() 함수. lstrip의 l은 left, rstrip의 r은 right를 의미한다.

blank_test = " it is ik "
blank_test.lstrip()

# "it is ik " blank_test.rstrip()
# " it is ik" blank_test.strip()
# "it is ik"

 

  문자열에서 특정 문자열을 대체해주는 replace()함수

name = "itisik"
name.replace("k", "king")
# "itisiking"

  구분자(Separator)를 이용하여 문자열을 나눠주는 split()함수

name = "itisik"
name.split("i")
# ["t", "s", "k"]

csv = "apple,orange,banana"
csv.split(",")
# ["apple", "orange", "banana"]

 

  여기까지 짧지 않은 파이썬 문자형 자료형에 대한 내용이었다. 다음 포스트에서는 나열하는 자료형인 리스트에 대해서 알아보고자 한다.

반응형