1. 문자열(String)

이번에 알아볼 자료형은 문자열(String)이며, 문자열은 문자들의 모임, 문자를 나열한 것을 문자열이라고 합니다. 'a', 'b', 'c' 등과 같은건 문자라고 할 수 있지만 "abc"와 같이 문자들이 모이게 되면 이것을 문자열이라고 할 수 있습니다. 파이썬에서 문자열은 단일 인용부호(')나 이중 인용부호(")로 감싸주어 표현합니다. 주의하실 점은, 감싸줄 때는 단일 인용부호로 시작했으면 단일 인용부호로 끝나야 하며, 이중 인용부호로 시작했으면 이중 인용부호로 끝나야만 한다는 것을 기억하시기 바랍니다. 아래의 예는 모두 문자열이라고 할 수 있습니다.

>>> type("ABCDEFGHI")
<class 'str'>
>>> type('ABC')
<class 'str'>
>>> type("1301##")
<class 'str'>

그리고 파이썬에서는 위 방법뿐만 아니라 두가지 방법이 더 존재하는데, 이는 단일 인용부호나 이중 인용부호를 연속으로 세 번 연속으로쓴 """와 '''가 있습니다. 이런 연속된 인용부호를 쓰게되면 간단하게 여러 줄의 문자열을 변수에 대입하거나 출력할 수 있습니다. 아래의 예제를 한번 보도록 합시다.

>>> print("""
ABCDEFGHIJKL
0123456789
!@#$%^&*
""")

ABCDEFGHIJKL
0123456789
!@#$%^&*

위 예제를 보시면 연속된 인용부호의 사용은 여러 줄의 문자열을 보다 쉽게 출력하는 것을 가능하게 합니다. 단일 혹은 이중 인용부호의 사용으로 여러 줄의 문자열을 나타내게 하려면 이스케이프 문자를 사용하여야만 합니다. 여기서 이스케이프 문자란 별도의 기능을 제공하는 특수한 문자로 앞에 역슬래시(\)가 있습니다. 아래의 표는 주로 쓰이는 이스케이프 문자를 정리해둔 것입니다.

이스케이프 문자

설명

\n

개행(Newline, 줄바꿈)

\t

탭(Tab)

\0

NULL 문자

\\

문자 '\'

\'

단일 인용부호(')

\"

이중 인용부호(")

위 표에 정리된 이스케이프 문자를 한번 사용하여 보도록 합시다. 아래 예제에서는 개행 문자와 탭 문자를 사용했습니다.

>>> print("AAA\nB\tCDE")
AAA
B	CDE

결과를 보시면 AAA 바로 다음에 개행이 되고, B 다음에 탭 문자가 삽입된 것을 보실 수 있습니다. 만약에 역슬래시를 출력하려면, 위 표에 나온대로 역슬래시를 연속으로 두번을 써야 하는데 이는 역슬래시가 단독으로 쓰이면 이스케이프 문자로 인식하기 때문에, 아래와 같이 역슬래시를 두번 사용함으로 하나의 역슬래시를 출력할 수 있습니다.

>>> print("C:\\ABC.txt")
C:\ABC.txt

그리고 이중 인용부호(")나 단일 인용부호(')로 묶은 문자열 안에 이중 인용부호(") 또는 단일 인용부호(')를 포함하고 싶은 경우에는 앞에다 역슬래시(\)를 붙이거나, 이중 인용부호로 묶은 문자열 내에서 단일 인용부호를 사용하거나, 단일 인용부호로 묶은 문자열 내에서 이중 인용부호를 사용하면 됩니다. 아래와 같이 말입니다.

>>> print("\"It's all prepared. All I need to is move forward!\"")
"It's all prepared. All I need to is move forward!"
>>> print('"Try your best rather than be the best."')
"Try your best rather than be the best."
>>> print("'I determine my future all by myself.'")
'I determine my future all by myself.'
>>> print('\'Think different!\'')
'Think different!'

추가로, 아래와 같이 줄의 마지막에 역슬래시(\)를 사용하면 다음 줄과 현재 줄이 하나로 이어집니다.

>>> str = "가장 높은곳에 올라가려면 \
가장 낮은 곳부터 시작하라"
>>> print(str)
가장 높은곳에 올라가려면 가장 낮은 곳부터 시작하라


2. 문자열 연산(String operation)

파이썬에서는 문자열에 관련된 연산자들도 지원하고 있는데, 이 중에서 + 연산자는 문자열을 서로 연결하는 기능을 하며, * 연산자는 문자열을 반복하는 기능을 합니다. 

>>> "012" "3456789"
'0123456789'
>>> "ABC" + "DEFGHI"
'ABCDEFGHI'
>>> "Python!" * 3
'Python!Python!Python!'

위 예제의 첫줄에 적힌 코드에서는 + 연산자가 없어도 문자열이 서로 연결된 것을 보실 수 있습니다. 이는 값이 고정되어 있는 문자열 상수 끼리는 + 연산자를 생략할 수 있기 때문입니다. 그리고 세번째 줄에 쓰인 + 연산자는 "ABC"와 "DEFGHI"를 서로 연결하여 "ABCDEFGHI"를 만들어 냅니다. 다섯번째 줄에 쓰인 * 연산자는 "Python!"을 3번 반복하는 기능을 하여 "Python!Python!Python!"를 만들어 내는 것입니다.


3. 인덱싱(Indexing)

파이썬에서는 문자열에서 원하는 위치에 있는 문자를 마음대로 꺼낼 수 있는데 이를 인덱싱(Indexing)이라 합니다. 변수 뒤에 가져오려는 문자의 위치를 적고, 그 위치를 대괄호로 감싸면 되며, 즉 '변수[위치]'와 같은 형태입니다. 대괄호 안에 들어가는 수를 위치, 첨자, 인덱스라고도 하며 이 위치는 1이 아닌 0부터 시작합니다. 예를 들어서 "python is very powerful"와 같은 문자열이 있다면, 각 문자의 위치는 아래 그림과 같습니다.

위 그림에서 예를 들어, 위치 4에 해당하는 문자는 'o', 위치 11에 해당하는 문자는 'e'입니다. 이를 직접 인덱싱하여 예상하던 결과가 맞는지 비교해보도록 합시다. 아래의 예제를 우선 봅시다.

>>> var = "python is very powerful"
>>> var[4]
'o'
>>> var[11]
'e'
>>> var[0]
'p'
>>> var[1]
'y'

위 코드의 결과를 보시니 우리가 생각하던 결과와 일치하죠? 그럼 위치에 음수가 들어가는 경우는 어떤 결과가 나올 것 같나요? 위치에 음수가 쓰이면 앞에서 부터가 아닌 뒤에서부터 문자열을 읽게 됩니다. 

위 그림에서 예를 들면, 위치 -2에 해당하는 문자는 'u', 위치 -10에 해당하는 문자는 'y', 위치 -16에 해당하는 문자는 'i'일 것입니다. 이를 직접 인덱싱하여 예상하던 결과가 맞는지 비교해보도록 합시다. 아래의 예제를 봅시다.

>>> var = "python is very powerful"
>>> var[-2]
'u'
>>> var[-10]
'y'
>>> var[-16]
'i'

위 코드의 결과와 예상했던 결과가 일치함을 알 수 있습니다. 주의하실 점은 아래와 같이 인덱싱을 통해 문자열의 일부를 수정하려고 하면 에러가 발생합니다. 인덱싱을 통해서 문자열을 변경하는 행위는 허용되지 않는다는 의미입니다.

>>> var = "ABCDE"
>>> var[2] = 'G'
Traceback (most recent call last):
  File "<pyshell#66>", line 1, in <module>
    var[2] = 'G'
TypeError: 'str' object does not support item assignment


4. 슬라이싱(Slicing)

우리가 전에 알아본 인덱싱(indexing)이 원하는 위치에 있는 문자를 가져올 수 있는 것이라면, 이번에 배울 슬라이싱(Slicing)을 통해 문자열을 통채로 꺼낼 수 있습니다. 슬라이싱이라는 단어만 보고도 케이크를 자르듯 문자열을 조각조각 썰어버릴 것 같은 느낌이 들지 않나요? 쉽게 말하면 슬라이싱을 통해서 문자열을 조각내어 일부만 가져온다고 할 수 있습니다. 슬라이싱은 '변수[시작 위치:끝 위치]'와 같이 사용하며, 이는 시작 위치부터 시작해서 끝 위치 까지의 문자열을 가져온다는 것입니다.

위의 그림처럼 위치 2~5에 있는 문자열의 일부를 가져오고 싶다면 [2:5]라고 써야한다고 생각하겠지만, 끝 번호에 해당하는 문자는 포함이 되지 않습니다. 즉, 위 그림의 문자열을 가져오려면 [2:6]라고 써야합니다. 상당히 혼동이 오실지도 모르겠는데, 여러번 사용하다 보면 적응되니 걱정하지 않으셔도 될 듯 합니다. 우선 한번 사용해보도록 합시다.

>>> var = "python is best language ever"
>>> var[2:6]
'thon'
>>> var[3:7]
'hon '
>>> var[0:15]
'python is best '

위 코드에서 [2:6]은 위치 2에서 위치 5까지의 문자열을 가져옵니다. (위에서 말한대로, 끝 위치에 존재하는 문자는 포함되지 않기 때문에 6은 포함하지 않습니다) [3:7]은 위치 3에서 위치 6까지의 문자열을, [0:15]는 위치 0에서 위치 14까지의 문자열을 가져오는 것입니다. 인덱싱과 마찬가지로 시작 위치와 끝 위치에 음수가 들어갈 수 있는데, 이는 문자열을 가장 뒤에서부터 읽어서 문자열을 잘라올 수 있습니다.

위 문자열에서 위치 -13부터 시작하여 위치 -6까지의 문자열을 가져오려면, [-13:-5]라고 써야 합니다. 여기도 마찬가지로 위치 -5에 해당하는 문자는 포함이 되지 않기 때문에 실제로는 위치 -13부터 위치 -5까지의 문자열을 가져옵니다. 아래의 예를 한번 보도록 합시다.

>>> var = "python is best language ever"
>>> var[-13:-5]
'language'
>>> var[-15:-6]
't languag'

위 코드와 결과를 보시면, 우리의 예상대로 "language"라는 일부 문자열을 가져왔음을 확인하실 수 있습니다. 이번에는 한번 처음 위치나 끝 위치를 생략하여 결과를 살펴보도록 하겠습니다.

>>> var = "0123456789"
>>> var[2:]
'23456789'
>>> var[:5]
'01234'
>>> var[:]
'0123456789'

위 코드와 결과에서 끝 위치를 생략하면 처음 위치부터 시작하여 끝까지 문자열을 읽어오며, 시작 위치를 생략하면 처음부터 끝 위치까지 문자열을 읽어오고, 둘 다 생략하면 처음부터 끝을 읽어오라는 의미이기 때문에 문자열 전체를 가져오게 됩니다.


슬라이싱이 대충 어떤 기능을 하는 녀석인지 감이 오시나요? 이번에는 슬라이싱을 좀 더 확장해보도록 하겠습니다. 위에서는 시작 위치와 끝 위치만 사용되다가, 확장 슬라이싱에서는 스텝(step)이라는 녀석이 추가됩니다. 스텝을 우리가 알기 쉬운 말로 바꾸어 보면, '보폭'이나 '간격, 단위'로 말할 수 있습니다. 예제를 직접 보는게 빠르겠죠?

>>> temp = "123456789"
>>> temp[::3]
'147'
>>> temp[::-1]
'987654321'
>>> temp[::-2]
'97531'

위의 예제에서 결과를 살펴보니, 순서대로 3칸 단위로 데이터를 가져오고, 거꾸로 데이터를 가져오고, 거꾸로 2칸 단위로 데이터를 가져온다는 것을 확인하실 수 있습니다. 그림으로 확인해보면 아래와 같을 것입니다.

위 그림을 보니, temp[::3]이 왜 147이란 값이 나오게 되었는지 짐작이 가시나요? temp[::-2]도 위와 마찬가지로 거꾸로 2칸 단위로 옮겨간다고 생각하면 왜 97531이 나오게 되었는지도 알 수 있을 것입니다.


5. 문자열의 서식 지정(Formatting)

마지막으로 문자열의 서식 지정에 대해서 알아보도록 하겠습니다. 문자열의 서식을 지정하는 방법에는 튜플을 이용하는 방법, format 함수를 이용하는 방법, format 메서드를 이용하는 방법이 있으며, 이 세가지 방법을 모두 알아보려고 합니다. 우선은 먼저 튜플을 이용하는 방법부터 보도록 하겠습니다.

>>> print("제 나이는 %d이며, 몸무게는 %.1f kg이고, 취미는 %s입니다. " % (19, 62.5, '프로그래밍'))
제 나이는 19이며, 몸무게는 62.5 kg이고, 취미는 프로그래밍입니다. 

위 예제를 살펴보시면 '%d'나 '%s', '%f'와 같은 것이 사용된 것을 확인하실 수 있습니다. 이러한 문자들을 서식 문자라고 하며, 각각 정수형과 문자열, 실수형 데이터를 지정하게 됩니다. 참고로 '%.1f'와 같이 앞에 숫자가 포함되어 있는 서식 문자는 출력할 자릿수나 정밀도 등을 나타내며, 이는 소수점 이하 한자리만 출력한다는 것입니다. 이번에는 format 함수를 통하여 문자열의 서식을 지정해보도록 하겠습니다.

>>> weight = 62.53
>>> print("몸무게:", format(weight, '.1f'))
몸무게: 62.5
>>> print("돈:", format(12931401, ',d'))
돈: 12,931,401

위 예제에서는 format 함수를 통하여 변수 weight의 값을 소수점 이하 한자리로 출력하고 있으며, 정수형 데이터인 12931401을 천 단위마다 쉼표를 추가하였습니다. ',d'와 같이 앞에 쉼표를 붙여주면 천 단위마다 쉼표를 추가할 수 있게 됩니다. 간단하죠? 그리고 이제는 format 메서드를 통해서 문자열의 서식을 지정해보도록 하겠습니다.

>>> '{} {}'.format('홍길동', 34)
'홍길동 34'

위 예제를 보시면 중괄호로 둘러싸인 곳에는 데이터가 위치하게 되며, 순서대로 중괄호 쪽에 데이터가 들어가는 것을 확인하실 수 있습니다. 이번에는 출력되는 순서를 한번 바꾸어 보도록 하겠습니다.

>>> '{0} {1} {2}'.format(12, 34, 56)
'12 34 56'
>>> '{2} {2} {1} {0}'.format(12, 34, 56)
'56 56 34 12'

위 예제를 보시면 중괄호 내에 '{0}', '{1}', '{2}'와 같이 숫자가 들어간 것을 확인하실 수 있습니다. {0}은 format 메서드의 첫번째 인수가 들어가고, {1}은 두번째 인수가 들어가게 됩니다. 그리고 위처럼 순서를 변경할 수 있으며, '{2} {2}'와 같이 여러 번 등장할 수 있습니다. 

>>> '{} / {} = {:.2f}'.format(5, 2, 5 / 2)
'5 / 2 = 2.50'
>>> '{0} / {1} = {2:.4f}'.format(13, 3, 13 / 3)
'13 / 3 = 4.3333'

튜플을 이용한 방법이나 format 함수를 이용한 방법과 같이 위 예제처럼 format 메서드를 통한 방법도 자릿수나 정밀도 등을 지정해 줄 수 있습니다. {:.2f}에는 5 / 2의 결과가 들어가게 되는데, 5 / 2는 2.5고 .2f를 통하여 소수점 이하 두자리까지만 출력하게 되므로 2.50이 나오는게 정상입니다. 

>>> lst = [30, 40, 50, 80, 90, 100]
>>> 'lst[4] = {0[4]}'.format(lst)
'lst[4] = 90'

위 예제처럼 리스트가 인수로 전달될 때 인덱싱을 통해서 접근할 수 있기도 합니다. {0[4]}에는 lst[4]의 값이 들어가게 되는 셈입니다. 더 구체적으로 살펴보자면, {0}라고 썼을 경우에는 리스트가 인수로써 그대로 전달되지만 {0[4]}와 같이 작성했을 경우에는 인덱싱으로 전달받은 리스트의 요소를 꺼내올 수 있습니다.

>>> '제 나이는 {age}살이고, 제 몸무게는 {weight} kg 입니다.'.format(age = 19, weight = 72.5)
'제 나이는 19살이고, 제 몸무게는 72.5 kg 입니다.'

그리고 위 예제처럼 이름을 통하여 값을 가져올 수 있기도 합니다. 그 다음에는, 보조적인 기능을 지원하는 서식 문자에 대해서 살펴보도록 하겠습니다. 공백이나 부호 등과 관련된 서식 문자를 차례대로 살펴보도록 할텐데, 먼저 공간을 확보하는 서식 문자부터 시작하여 차례대로 알아가보도록 하겠습니다.

>>> '{0:6s}'.format('cat')
'cat   '
>>> '{0:5d}'.format(334)
'  334'

위 예제의 첫번째 코드를 해석하면 최소 6칸의 자리를 확보하고나서 문자열인 cat을 출력하라는 것입니다. 만약 위 예제에서 'cat'이 아니라, 'python'처럼 길이가 6 이상인 문자열을 넘기면 공백없이 출력이 됩니다. 두번째 코드도 마찬가지로 최소 5칸의 자리를 확보하고나서 정수 334를 출력하라는 것이 됩니다.

>>> '{0:<10d}'.format(1234)
'1234      '
>>> '{0:>10d}'.format(1234)
'      1234'
>>> '{0:^10d}'.format(1234)
'   1234   '

이처럼 개발자가 임의로 왼쪽으로 맞추어 출력할 것인지, 오른쪽으로 맞추어 출력할 것인지, 가운데를 맞추어 출력할 것인지도 지정할 수도 있습니다. 확보된 공간 내에서 <를 통해 왼쪽 정렬을, >를 통해 오른쪽 정렬, ^을 통해 가운데 정렬을 할 수 있다는 것입니다. 만약, 빈 공간을 0으로 채우고 나서 출력하고 싶을 때에는 아래와 같이 작성해주시면 됩니다.

>>> '{0:-<10d}'.format(1234)
'1234------'
>>> '{0:=>10d}'.format(1234)
'======1234'
>>> '{0:*^10d}'.format(1234)
'***1234***'

만약에 정렬 시 생겨나는 공백을 다른 문자로 대체하고 싶다면 위와 같이 입력하시면 됩니다. 여기서 주의하실 부분은 >, <, ^ 전에 입력하셔야 합니다.

>>> '{0:07d}'.format(1234)
'0001234'

위 예제에서 7칸을 확보하고 나서 앞에 빈 공간은 모두 0으로 채워진 것을 보실 수 있습니다. 이렇게 10진수 정수를 나타내는 것은 충분히 알겠는데, 8진수나 16진수를 나타내고 싶은 경우에는 어떻게 할까요?

>>> '{0:#o} {0:#x}'.format(123)
'0o173 0x7b'

위와 같이 8진수라면 #o를 통해 앞에 0o를, 16진수라면 #x를 통해서 앞에 0x를 붙일 수 있습니다. 소문자 x가 아닌 대문자 X를 사용하면 0X를 앞에 붙일 수도 있습니다. 좀 더 살펴보면 백분율이나 부호 등에 관한 서식 문자가 더 존재하기는 하지만, 주로 쓰이는 서식 문자에 대해 간단하게 알아보는 정도로 마치도록 하겠습니다.   


6. 문자열 메서드

  대문자로 변환하는 upper, 소문자로 변환하는 lower

>>> s = 'abCdeFg'
>>> s.upper()
'ABCDEFG'
>>> s.lower()
'abcdefg'

소제목 그대로 upper는 문자열 내의 소문자를 모두 대문자로 변환해주는 메서드이며, lower는 문자열 내의 대문자를 모두 소문자로 변환해주는 메서드라고 할 수 있습니다.  


  문자열 위치를 찾아내는 find

>>> s = 'It`s always such a pleasure'
>>> s.find('way')
7
>>> s.find('such', 13)
-1
>>> s.find('the')
-1

find 메서드는 임의의 문자열 내에서 찾고자 하는 부분 문자열이 있을때, 검색을 통해 찾아낸 부분 문자열의 위치를 반환해주는 메서드입니다. 만약 찾고자 하는 문자열을 찾지 못했을 경우에는 -1를 반환합니다.

  부분 문자열의 발생 횟수를 알려주는 count

>>> s = 'we are invincible, we are unique'
>>> s.count('we')
2
>>> s.count('in')
2

count 메서드는 임의의 문자열 내에서 부분 문자열의 등장 횟수를 반환합니다. 위의 예제의 결과에서는,

we are invincible, we are unique 

'we'와 'in'이 각각 2번씩 등장하여 반환된 결과값이 모두 2로 출력된 것입니다.

  새로운 문자열로 교체하는 replace

>>> s = 'AB-C-D-EFGH'
>>> s.replace('-', '')
'ABCDEFGH'

replace 메서드는 원본 문자열을 새로운 문자열로 바꾸어 줍니다. 위 예제를 보면, 문자열 s에 있는 -를 공백으로 모두 치환한 결과가 나왔음을 보실 수 있습니다. 

  좌우 공백을 제거하는 strip

>>> s = '      1234 56   '
>>> s.strip()
'1234 56'

strip 메서드는 양쪽의 공백을 모두 제거하는 역할을 하며, 왼쪽의 공백만 제거하는 lstrip, 오른쪽의 공백만 제거하는 rstrip라는 메서드도 있으니 참고하시길 바랍니다.

  문자열을 분리하는 split

>>> s = '1/2/3/4/5/6'
>>> s.split('/')
['1', '2', '3', '4', '5', '6']
>>> lst = s.split('/')
>>> lst[3]
'4'

split 메서드는 구분자(sep)를 넘겨주면 그 구분자를 기준으로 문자열을 쪼개는 역할을 합니다. 위의 예제에서, '/'를 구분자로 두고 쪼개면 각각 '1', '2', '3', '4', '5', '6'이 나오며 결과는 리스트형으로 반환되는 것을 알 수 있습니다. 

  문자열을 결합하는 join

>>> lst = ['1', '2', '3', '4', '5', '6']
>>> sep = "-"
>>> sep.join(lst)
'1-2-3-4-5-6'

join 메서드는 구분자(sep)를 통해 각각의 리스트 요소들을 순서대로 연결하는 역할을 합니다. 위 예제를 살펴보시면, 구분자인 '-'를 통해 각각의 요소가 연결됨으로써 '1-2-3-4-5-6'이라는 문자열이 반환됨을 확인하실 수 있습니다.


이해가 되시나요? 개념이 잘 이해가 되지 않더라도 조급해하지 마시고 천천히 읽어보셔서 이해를 해보시길 바랍니다.


Q1. 문자열 문제 (☆☆☆)

아래의 문장을 연속된 이중부호의 사용 혹은 이스케이프 문자를 사용하여 출력해보세요.



성공은 최종적인 게 아니며

실패는 치명적인 게 아니다.

중요한 것은 지속하고자 하는 용기다.


- 윈스턴 처칠



Q2. 문자열 연산 문제 (☆☆☆)

+ 연산자와 * 연산자를 사용하여 아래의 결과가 출력되도록 작성하세요.


파이썬은 매우매우매우매우매우매우매우매우매우매우매우매우매우매우 쉽다.

(참고로 위 문장에서 '매우'는 14번 등장했습니다.)


Q3. 인덱싱 문제 (☆☆☆)

아래의 결과를 예측해보세요.

>>> var = "ABC123DEF456GHI789"
>>> var[2]
'?'
>>> var[-6]
'?'
>>> var[8]
'?'

Q4. 슬라이싱 문제 (☆☆)

아래의 문장에서 슬라이싱을 통해 Trial and error와 ladder란 단어를 가져와 출력해보세요.


'Trial and error' is a ladder that reaching for the truth.


Q5. 문자열 서식 지정 문제 (☆☆☆)

오늘의 날짜를 문자열 서식을 통해 출력해보세요. (예: 오늘은 2015년 1월 8일입니다.)