Skip to article frontmatterSkip to article content
Site not loading correctly?

This may be due to an incorrect BASE_URL configuration. See the MyST Documentation for reference.

10 문자열 인덱싱, 슬라이싱

Updated: 30 mrt 2026

문자열은 포함된 문자와 기호의 순서를 중요하게 여기는 순차 자료형sequence type이다. 따라서 문자열의 항목으로 포함된 문자와 기호의 순서가 다르거나 사용된 문자열의 길이가 다르면 서로 다른 문자열로 처리된다.

'ab' == 'ba'
False
'aa' == 'aaa'
False

대소문자도 구별된다.

"python" == "Python"
False

순차 자료형으로서의 문자열을 다루는 다양한 기법을 살펴본다.

10.1문자열 인덱싱

문자열은 문자와 기호들 사이의 순서가 절대적으로 중요하다. 문자열 왼편에 위치한 항목부터 차례대로 0, 1, 2, 3 등의 인덱스index를 부여받는다. 인덱스를 이용하여 문자열에 포함된 정보를 확인하고 추출한다.

인덱스의 대표적인 활용법이 문자열 인덱싱indexing이다. 인덱싱은 인덱스를 이용하여 문자열의 항목을 확인한다. 설명을 위해 아래 문자열을 이용한다.

colors = 'red, blue, yellow'
  • 0 번 인덱스 값

colors[0]
'r'
  • 3 번 인덱스 값

colors[3]
','

인덱스를 문자열 오른쪽에서부터 차례대로 -1, -2, -3 등 음수로 지정할 수도 있다.

  • 오른쪽 끝에 위치한 문자

colors[-1]
'w'
  • 오른쪽 끝에 두 번째 문자

colors[-2]
'o'

문자열의 길이에 따라 사용할 수 있는 인덱스의 구간이 정해진다. colors 변수가 가리키는 문자열은 길이가 17이기에 0부터 16까지의 정수 또는 -1부터 -17까지의 정수만 인덱스로 사용할 수 있다.

len(colors)
17

-17보다 작거나 16보다 큰 경우 IndexError 오류가 발생한다.

colors[50]
---------------------------------------------------------------------------
IndexError                                Traceback (most recent call last)
Cell In[10], line 1
----> 1 colors[50]

IndexError: string index out of range
colors[-20]
---------------------------------------------------------------------------
IndexError                                Traceback (most recent call last)
Cell In[11], line 1
----> 1 colors[-20]

IndexError: string index out of range

10.2문자열 슬라이싱

인덱스의 특정 구간에 속하는 부분 문자열을 추출할 때 슬라이싱slicing을 사용한다. 슬라이싱은 다음과 같이 실행한다.

문자열[시작인덱스:끝인덱스:보폭]

시작과 끝은 슬라이싱 구간의 시작과 끝 인덱스를 가리키며 보폭은 항목 선택 규칙을 지정한다.

  • 시작인덱스 : 시작 인덱스부터 문자 확인

  • 끝인덱스 : 끝 인덱스 이전까지의 문자 확인

  • 보폭: 시작 인덱스부터 몇 보폭씩 건너뛰며 문자를 추출할지 결정. 보폭의 크기가 1이면 생략 가능.

colors에서 red를 추출하고 싶다면 다음과 같이 하면 된다. 이유는 r의 인덱스는 0이고, d의 인덱스는 2이기 때문이다.

colors = 'red, blue, yellow'

colors[0:3]
'red'

보폭을 1로 지정해도 동일한 결과를 얻는다.

colors[0:3:1]
'red'

colors에서 5번 인덱스의 문자인 b부터 끝까지 하나씩 건너 뛰면서 추출하려면 다음과 같이 한다.

colors[5:len(colors):2]
'bu,ylo'

양의 정수와 음의 정수를 섞어서 인덱스로 사용할 수 있다. -1은 오른쪽 끝의 문자를 가리키는 인덱스임에 주의한다.

colors[5:-1:2]
'bu,ylo'

슬라이싱 인덱스의 기본값

시작인덱스, 끝인덱스, 보폭 각각의 인자는 경우에 따라 생략될 수도 있다. 그럴 때는 다음과 같이 지정된 기본값이 적용된다.

  • 시작인덱스의 기본값 : 0

  • 끝인덱스의 기본값 : 문자열의 길이

  • 보폭의 기본값 : 1

  • colors[0:3:1]

colors[:3:]
'red'
  • colors[5:len(colors):2]

colors[5::2]
'bu,ylo'

보폭을 생략할 때는 둘째 콜론(:)도 함께 생략할 수 있다.

  • colors[0:3]

colors[:3]
'red'

슬라이싱 인덱스의 범위

문자열의 인덱스 범위를 벗어나는 값으로 슬라이싱을 실행해도 오류가 발생하지 않는다. 대신 문자열의 좌 또는 우 끝까지만 슬라이싱이 적용된다.

colors[-30:100]
'red, blue, yellow'
colors[5:100:3]
'beyl'

역순 슬라이싱

슬라이싱은 기본적으로 작은 인덱스에서 큰 인덱스 방향으로 확인한다. 하지만 보폭을 음의 정수로 지정하면 역순으로 항목을 추출한다. 역순으로 슬라이싱을 지정하려면 시작인덱스가 끝인덱스보다 커야 한다.

colors[-2:-8:-3]
'oe'

보폭이 -1이고, 시작 인덱스와 끝 인덱스를 생략하면 문자열 전체를 역순으로 추출한다.

colors[::-1]
'wolley ,eulb ,der'

10.3불변 자료형: 문자열

문자열은 불변immutable 자료형이다. 즉, 한 번 생성된 문자열은 수정할 수 없다. 따라서 인덱싱 또는 슬라이싱을 사용하여 값의 일부를 변경하려 시도하면 수정을 허용하지 않는 자료형을 수정하려 시도한다는 의미에서 TypeError가 발생한다.

예를 들어 아래 그림은 “Michael Jackson” 문자열에 포함된 항목을 인덱싱으로 수정할 수 없음을 보여준다. 심지어 대문자 'J’를 동일한 문자로 교체하는 것도 허용되지 않는다.

위 그림의 내용을 코드로 작성하면 다음과 같다.

Name = "Michael Jackson"
Name[8] = 'J'
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
Cell In[23], line 2
      1 Name = "Michael Jackson"
----> 2 Name[8] = 'J'

TypeError: 'str' object does not support item assignment

위 그림은 또한 기존의 문자열을 이용하여 새로운 문자열을 생성하는 일은 언제든지 가능함을 보여준다.

Name = Name + " is the best"
Name
'Michael Jackson is the best'

10.4문자열 메서드

문자열 자료형에만 사용하는 함수들이 있다. 이와같이 특정 자료형에만 사용하는 함수들을 메서드method라 부른다. 메서드는 일반적인 함수와는 달리 특정 자료형의 값을 먼저 언급하고 바로 이어서 점(.)과 함께 실행한다.

문자열 자료형은 다양한 메서드를 제공한다. 여기서는 아래 메서드의 기능만 살펴 본다.

Table 1:문자열 주요 메서드

기능

메서드

설명

탐색

count()

인자로 지정된 문자열이 사용된 빈도

find()

인자로 지정된 문자열이 시작하는 인덱스 반환. 지정된 문자열이 없다면 -1 반환

index()

인자로 지정된 문자열이 시작하는 인덱스 반환. 지정된 문자열이 없다면 오류 발생

startswith()

인자로 지정된 문자열로 시작하는지 여부 판단

endswith()

인자로 지정된 문자열로 끝나는지 여부 판단

소문자/대문자

lower()

기존 문자열과 동일하지만 모든 영어 알파벳이 소문자인 문자열 반환

upper()

기존 문자열과 동일하지만 모든 영어 알파벳이 대문자인 문자열 반환

교체/삭제

replace()

기존 문자열에서 첫째 인자로 지정된 문자열만 둘째 인자로 교체된 새로운 문자열 반환

strip()

기존 문자열의 양끝에서 인자로 지정된 문자열 안에 포함된 모든 문자가 최대한 많이 삭제된 문자열 반환.

쪼개기/결합

split()

기존 문자열을 쪼개서 인자로 지정된 문자열에 포함된 기호들을 기준으로 쪼개서 생성된 부분 문자열들로 구성된 리스트 반환.

join()

여러 개의 문자열을 인자로 지정된 기호로 연결해서 생성한 문자열 반환

10.4.1탐색 메서드

아래 문자열을 이용하여 먼저 탐색과 관련된 메서드의 기능을 살펴 본다.

words = " \tMy life is so so cool! \n"

count() 메서드

인자로 지정된 문자열이 몇 번 등장하는지를 확인한다. 예를 들어 'so' 문자열은 words에 두 번 등장한다.

words.count('so')
2

반면에 'soo' 문자열은 words 문자열에 등장하지 않는다.

words.count('soo')
0

find() 메서드

지정된 문자열이 처음 시작하는 곳의 인덱스를 확인한다. 예를들어, 'cool' 문자열은 words 문자열의 19 번 인덱스부터 시작한다.

words.find('cool')
19

등장하지 않으면 -1을 반환한다. 예를 들어 'col' 문자열은 words 문자열에 등장하지 않는다.

words.find('col')
-1

index() 메서드

지정된 문자열이 처음 시작하는 곳의 인덱스를 확인한다. 'cool' 문자열은 words 문자열의 19 번 인덱스부터 시작한다.

words.index('cool')
19

등장하지 않으면 오류가 발생한다. 예를 들어 'col' 문자열은 words 문자열에 등장하지 않는다.

words.index('col')
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
Cell In[31], line 1
----> 1 words.index('col')

ValueError: substring not found

startswith() 메서드

지정된 문자열로 시작하는지 여부를 판정한다. 예를 들어 words 문자열은 ' \tMy' 문자열로 시작한다.

words.startswith(' \tMy')
True

반면에 'My' 문자열로 시작하진 않는다.

words.startswith('My')
False

endswith() 메서드

지정된 문자열로 끝나는지 여부를 판정한다. 예를 들어 words 문자열은 'cool!' 문자열로 끝나지 않는다.

words.endswith('cool!')
False

대신 'cool! \n' 문자열로 끝난다.

words.endswith('cool! \n')
True

10.4.2새로운 문자열 생성 메서드

지금부터 언급되는 메서드는 word 문자열 자체는 그대로 두고 새로운 문자열을 생성한다.

words = " \tMy life is \tso so cool! \n"

lower() 메서드

모든 영어 알파벳을 소문자로 변경한 문자열을 반환한다. 예를 들어 아래 코드는 word 문자열에 포함된 모든 문자열을 소문자로 변경한 문자열을 생성한다.

words.lower()
' \tmy life is \tso so cool! \n'

upper() 메서드

모든 영어 알파벳을 대문자로 변경한 문자열을 반환한다. 예를 들어 아래 코드는 word 문자열에 포함된 모든 문자열을 대문자로 변경한 문자열을 생성한다.

words.upper()
' \tMY LIFE IS \tSO SO COOL! \n'

replace() 메서드

지정된 부분 문자열이 지정된 다른 문자열로 교체된 문자열을 반환한다. 예를 들어 아래 코드는 word 문자열에 포함된 so 문자열을 모두 that 으로 변경한 문자열을 생성한다.

words.replace('so', 'that')
' \tMy life is \tthat that cool! \n'

strip() 메서드

인자를 지정하지 않으면 문자열 양끝에 위치한 모든 화이트 스페이스를 삭제한 문자열을 반환한다. 양끝이 아닌 경우의 화이트 스페이스는 그대로 둔다.

words_stripped = words.strip()
words_stripped
'My life is \tso so cool!'

인자 문자열을 지정하면 인자에 포함된 모든 기호를 문자열 양끝에서 최대한 많이 삭제한 문자열을 반환한다. 아래 코드는 양끝에서 공백 ' ', 탭 '\t', 줄바꿈 '\n', 느낌표 '!', 소문자 와이 'y', 대문자 엠 'M'을 최대한 많이 삭제한다. 이 경우에도 지정된 문자열이 아닌 다른 문자열로 감싸인 다른 문자는 그대로 남는다.

words.strip(' \t\n!yM')
'life is \tso so cool'

split() 메서드

인자를 지정하지 않으면 공백 기준으로 쪼갠 문자열들로 구성된 리스트를 반환한다. 이 과정에서 쪼개진 문자열 양끝에 있는 화이트 스페이스는 모두 제거된다.

words.split()
['My', 'life', 'is', 'so', 'so', 'cool!']

문자열을 인자로 지정하면 해당 문자열을 기준으로 쪼개진 단어들의 리스트를 생성한다. 예를 들어 아래 문자열은 단어들 사이에 하이픈 "-"이 위치한다.

hyphen_words = 'My-life-is-so-so-cool!'

위 문자열을 "-"을 기준으로 쪼개면 다음과 같다.

hyphen_words.split("-")
['My', 'life', 'is', 'so', 'so', 'cool!']

join() 메서드

여러 개의 문자열을 결합한다. join() 메서드를 실행하는 문자열은 지정된 항목들을 이어붙이는 연결고리 역할을 수행한다.

예를 들어 아래 코드는 hello 문자열에 포함된 모든 문자열들 사이에 별표 기호를 추가하여 새로운 문자열을 생성한다.

'*'.join('hello')
'h*e*l*l*o'

문자열로 구성된 리스트가 인자로 사용되면 항목으로 포함된 모든 문자열을 결합한다. 예를 들어 아래 코드는 하이픈을 공백으로 대체하여 정상적인 문자열을 생성한다.

words_splitted = hyphen_words.split("-")
words_splitted
['My', 'life', 'is', 'so', 'so', 'cool!']
' '.join(words_splitted)
'My life is so so cool!'

10.5메서드 연속 적용

새로운 문자열을 생성하는 메서드에 다른 문자열 메서드를 연속해서 적용하면 매우 효율적으로 원하는 문자열을 생성할 수 있다. 예를 들어, 아래 코드는 문자열 양끝에서 화이트 스페이스를 제거하면 'My'로 시작함을 확인해준다.

words.strip().startswith('My')
True
words.strip()
'My life is \tso so cool!'

위 방식이 허용되는 이유는 메서드를 실행하는 표현식과 메서드의 반환값을 동일시되기 때문이다. 즉, words.strip()와 문자열 My life is \tso so cool!이 동일시되며, 따라서 startswith() 메서드 등 다른 문자열 메서드를 연속해서 적용할 수 있다.

반면에 아래 코드는 먼저 소문자로 변경한 다음에 화이트 스페이스 기준으로 쪼갠다.

words.lower().split()
['my', 'life', 'is', 'so', 'so', 'cool!']

join() 메서드를 연속 적용하는 방법은 다음과 같다. 아래 코드는 하이픈 기호를 기준으로 쪼갠 다음에 공백으로 쪼개진 단어를 이용하여 연결한다. 그 결과 문자열에 포함된 하이픈 기호가 제거된 문자열이 생성된다.

' '.join(hyphen_words.split("-"))
'My life is so so cool!'

10.6예제

예제 1

아래와 같이 선언된 lyrics변수가 있다.

lyrics = "\t When you're smiling, the whole world smiles with you.\n\t "

(1) lyrics가 가리키는 문자열이 대문자 W로 시작하는지 여부를 판단하는 한 줄 코드를 작성하라. 단, 화이트 스페이스는 무시한다.

답:

문자열 양 끝의 화이트스페이스를 제거한 다음에 바로 startswith() 메서드를 적용한다.

lyrics.strip().startswith('W')
True

(2) 위 문자열이 you.로 끝나는지 여부를 판단하는 한 줄 코드를 작성하라. 단, 화이트 스페이스는 무시한다.

답:

문자열 양 끝의 화이트스페이스를 제거한 다음에 바로 endswith() 메서드를 적용한다.

lyrics.strip().endswith('you.')
True

(3) 문자열 양 끝에 있는 화이트 스페이스를 모두 삭제하고, 모든 문자는 소문자로 변환된 문자열을 생성하는 한 줄 코드를 작성하라. 또한 "you're" 대신에 "you are" 가 사용되도록 해야 한다.

답:

문자열의 양 끝에 있는 공백, 줄바꿈, 탭 등의 화이트 스페이스는 strip() 메서드로 제거한다.

lyrics.strip()
"When you're smiling, the whole world smiles with you."

strip() 메서드의 반환값 또한 문자열이기에 바로 lower() 메서드를 적용하면 모든 철자가 소문자로 변환된 문자열이 생성된다.

lyrics.strip().lower()
"when you're smiling, the whole world smiles with you."

lower() 메서드 또한 문자열을 반환하기에 곧바로 replace() 메서드를 적용할 수 있다.

lyrics.strip().lower().replace("you're", "you are")
'when you are smiling, the whole world smiles with you.'

예제 2

문자열 'a:b:c:d' 을 이용하여 문자열 'a#b#c#d"을 생성하는 한 줄 코드를 작성하라.

abcd_colons = 'a:b:c:d'

힌트: split()join() 메서드 활용

답:

'#'.join(abcd_colons.split(':'))
'a#b#c#d'

예제 3

변수와 함수의 이름을 지정할 때 낙타camel 표기법 또는 팟홀pothole 표기법을 사용한다.

  • 낙타 표기법: 소문자로 시작하고, 이어지는 단어의 시작은 대문자로 작성하는 표기법.

  • 팟홀 표기법: 모두 소문자를 사용하고, 단어 사이에 밑줄기호(_)를 사용하는 표기법.

활용 예제는 다음과 같다.

  • 낙타 표기법 예제: userName, printMessage, countA 등.

  • 팟홀 표기법 예제: user_name, print_message, count_a 등.

아래 팟홀 표기법을 사용하는 문자열을 낙타 표기법으로 변환하는 한 줄 코드를 작성하라.

counting = 'one_Two_Three'

힌트: split()join() 메서드 활용

답:

"".join(counting.split('_'))
'oneTwoThree'

예제 4

어구전철anagram은 주어진 단어에 사용된 철자의 순서를 변경해서 생성되는 단어를 가리킨다. 예를 들어 "python"과 “thpyon” 서로 어구전철 관계다.

'python', 'thpyon' 두 문자열이 서로 어구전철임을 확인해주는 코드를 작성하라.

힌트: sorted() 함수 활용

답:

어구전철 관계의 두 단어는 사용하는 문자의 종류와 빈도가 동일하다. 따라서 두 문자열에 포함된 문자를 알파벳 순으로 정렬했을 때 동일한 값이 된다.

문자열에 포함된 문자를 정렬하기 이행 여기서는 sorted() 함수를 이횽한다. 함수의 반환값으로 문자열에 포함된 알파벳을 크기 순으로 정렬한 리스트가 지정된다.

sorted('python')
['h', 'n', 'o', 'p', 't', 'y']
sorted('thpyon')
['h', 'n', 'o', 'p', 't', 'y']

이제 주어진 두 단어의 어구전철 여부는 == 연산자로 바로 확인할 수 있다.

sorted('python') == sorted('thpyon')
True

예제 5

‘기러기’, ‘토마토’, ‘우영우’, ‘인싸 의사의 싸인’, ‘bob’, ‘eye’, 'pop’와 같이 앞으로 읽어도, 뒤로 읽어도 동일한 문자열을 회문palindrome이라 부른다.

주어진 문자열에서 공백을 무시할 때의 회문 여부를 확인하려 한다. 아래 문자열에서 공백을 모두 제거하면 회문이 됨을 보이는 코드를 작성하라.

힌트: 문자열 역순 슬라이싱

word = "여보게 저기 저게 보여"

답:

먼저 공백을 없애기 위해 split() 메서드와 join() 메서드를 활용한다.

word_list = word.split()
word_list
['여보게', '저기', '저게', '보여']
word_wo_space = ''.join(word_list)
word_wo_space
'여보게저기저게보여'

회문 여부는 문자열을 바로 읽었을 때와 역순으로 읽었을 때 결과가 동일한지 여부로 판단된다.

word_wo_space == word_wo_space[::-1]
True

예제 6

먼저 ord() 함수와 chr() 함수의 기능을 알아 본다.

ord() 함수

ord() 함수는 문자열에 사용될 수 있는 각각의 유니코드 기호에 정수를 부여한다. 예를 들어 숫자 0에서 9까지의 정수 숫자 문자열은 48부터 57까지의 정수가 부여되었다.

ord('0')
48
ord('1')
49
ord('8')
56
ord('9')
57

영어 소문자 알파벳 a부터 z까지 26개에 대해서는 97부터 122가 부여되었다.

ord('a')
97
ord('b')
98
ord('y')
121
ord('z')
122

반면에 영어 대문자 알파벳 A부터 Z까지 26개에 대해서는 65부터 90이 부여되었다.

ord('A')
65
ord('B')
66
ord('Y')
89
ord('Z')
90

chr() 함수

chr() 함수는 ord() 함수의 역함수에 해당한다. 즉, 정수를 하나의 기호에 대응시킨다.

예를 들어 48부터 57까지는 숫자 기호 '0'부터 '9'에 대응시킨다.

chr(48)
'0'
chr(49)
'1'
chr(56)
'8'
chr(57)
'9'

(1) 97부터 122까지는 영어 소문자 알파벳 'a'부터 'z'로 대응시킴을 확인하라.

답:

chr(97)
'a'
chr(98)
'b'
chr(121)
'y'
chr(122)
'z'

(2) 65부터 90까지는 영어 대문자 알파벳 'A'부터 'Z'로 대응시킴을 확인하라.

답:

chr(65)
'A'
chr(66)
'B'
chr(89)
'Y'
chr(90)
'Z'

(3) 영어 소문자 알파벳은 총 26개이다. a, b, c, ..., x, y, z 각각의 알파벳을 13칸씩 오른쪽으로 이동시키면 다음과 같은 대응 관계가 성립니다.

a => n
b => o
c => p
...
x => k
y => l
z => m

변수 alphabet'c'를 가리키도록 하자.

alphabet = 'c'

ord() 함수와 chr() 함수를 이용하여 변수 alphabet이 가리키는 값이 'z'가 되도록 하라.

답:

영어 알파벳이 26개 이기에 13번째 알파벳인 m까지는 ord() 값에 13을 더하면 원하는 알파벳이 지정된다. 실제로 m에 대응하는 알파벳은 z다.

chr(ord('m') + 13)
'z'

위 방식을 alphabet 변수에 적용하면 p가 나온다.

alphabet = chr(ord(alphabet) + 13)
print(alphabet)
p

(4) 변수 alphabet'x'를 가리키도록 하자.

alphabet = 'x'

ord() 함수와 chr() 함수를 이용하여 변수 alphabet이 가리키는 값이 'k'가 되도록 하라.

답:

영어 알파벳이 26개 이기에 13번째 알파벳인 m 이후 부터는 ord() 값에 13을 더하면 알바벳의 범위를 벗어난다. 예를 들어 n에 대항하는 기호가 여는 중괄호로 지정된다.

chr(ord('n') + 13)
'{'

하지만 영어 알파벳이 26개 이기에 이번에는 13을 빼면 원하는 결과를 얻는다.

chr(ord('n') - 13)
'a'

위 방식을 alphabet 변수에 적용하면 k가 나온다.

alphabet = chr(ord(alphabet) - 13)
print(alphabet)
k

예제 5

문자열의 islower() 메서드는 지정된 문자열이 모두 대문자 알파벳을 포함하지 않는지 여부를 판단한다. 즉, 소문자와 기타 기호만 포함할 때 True를 반환한다.

'abc'.islower()
True
'Abc'.islower()
False
'abc !'.islower()
True

isupper() 메서드는 반대로 판단한다.

'aBC'.isupper()
False
'ABC'.isupper()
True
'ABC !'.isupper()
True

다음 세 개의 함수는 모두 입력된 문자열이 소문자를 포함하고 있는지 여부를 조사하도록 구현되었지만 하나만 제대로 작동한다. 어느 함수가 제대로 작동하는지 확인한 다음 그 이유를 설명하라. 또한 다른 두 함수가 적절하게 구현되지 않은 이유를 설명하라.

def any_lowercase1(text):
    for c in text:
        if c.islower():
            return True
        else:
            return False

def any_lowercase2(text):
    for c in text:
        if 'c'.islower():
            return 'True'
        else:
            return 'False'

def any_lowercase3(text):
    flag = False
    for c in text:
        flag = flag or c.islower()
    return flag

아래 문자열에 대해 세 개의 함수를 테스트한다.

word1 = "ABcDE"
word2 = "ABCDE"

any_lowercase1() 함수

def any_lowercase1(text):
    for c in text:
        if c.islower():
            return True
        else:
            return False

인자로 입력되는 문자열의 첫 문자가 소문자의 대소문자 여부를 확인하고 바로 반환값을 지정한다. 함수는 반환값이 지정되면 바로 실행을 종료하기에 결국 첫 문자만 확인하고 종료한다. 따라서 word1 변수가 가리키는 문자열에 소문자 'c'가 포함되어 있지만 첫 문자가 대문자이기에 False를 반환한다.

any_lowercase1(word1)
False
any_lowercase1(word2)
False

any_lowercase2() 함수

def any_lowercase2(text):
    for c in text:
        if 'c'.islower():
            return 'True'
        else:
            return 'False'

for 반복문의 본문이 함수의 인자를 전혀 활용하지 않는다. 이유는 if 'c'.islower() 에서 사용된 'c'for c in textc와 아무 상관이 없는 영어 알파벳 c 하나로 구성된 문자열이기 때문이다. 또한 'c'가 소문자이기에 결과는 항상 문자열 'True'로 심지어 부울값 True와 아무 상관이 없다.

any_lowercase2(word1)
'True'
any_lowercase2(word2)
'True'

any_lowercase3() 함수

def any_lowercase3(text):
    flag = False
    for c in text:
        flag = flag or c.islower()
    return flag

flag 변수는 소문자를 찾았는지 여부를 기억한다. for c in text 반복문에서 ctext에 포함된 문자 하나하나를 가리킬 때 소문자를 만나는 순간 c.lower()True가 되고 따라서 or 연산자에 의해 flag이 계속해서 True를 가리키게 된다. 즉, 소문자가 하나라도 포함되면 True를 반환한다.

any_lowercase3(word1)
True
any_lowercase3(word2)
False

결국 any_lowercase3() 만 소문자 포함여부를 제대로 결정한다.

예제 6

문자열 find() 메서드에 대응하는 find() 함수를 직접 정의하라. 단, 두 개의 매개변수를 사용하며 각 매개변수의 기능은 다음과 같아야 한다.

  • 매개변수: 두 개의 문자열을 인자로 받는 word1word2 두 개 사용

  • word1word2를 부분 문자열로 포함할 경우 부분 문자열이 시작하는 인덱스 반환. 포함하지 않을 경우 -1을 반환.

단, 문자열 인덱싱, 슬라이싱만 사용하고 다른 문자열 메서드는 전혀 사용하지 않아야 한다.

예를 들어 'banana' 문자열은 'ana' 문자열을 부분 문자열로 포함한다. 'ana' 부분 문자열이 'banana' 문자열의 어느 인덱스에서 시작하는지를 확인하려면 모든 인덱스에 대해 그곳에서부터 'ana' 문자열의 시작하는지 여부를 슬라이싱으로 대조하면 된다.

예를 들어 1번 인덱스부터 'ana' 문자열이 시작하는지 여부는 다음과 같이 확인한다. 아래 코드에서 3은 'ana' 문자열의 길이를 나타낸다.

'banana'[1:1+3] == 'ana'

아래 find() 함수는 word1 문자열이 word2 문자열을 부분 문자열로 포함되는지 여부를 판단하기 위해 word1의 모든 인덱스에 대해 word2 부분 문자열과 일치 여부를 슬라이싱을 이용하여 확인하는 순간에 해당 인덱스를 반환한다. 또한 부분 문자열을 확인하지 못하면 -1을 반환한다.

def find(word1, word2):
    for idx in range(len(word1)):
        if word2 == word1[idx:idx+len(word2)] :
            return idx
    return -1
print(find('banana', 'ana'))
print(find('heyheyhey', 'ey'))
print(find('waikiki', 'ki'))
print(find('ulala', 'la'))
print(find('chukachuka', 'uKa'))
1
1
3
1
-1

10.7연습문제

문제 7

다음 세 개의 함수는 모두 입력된 문자열이 소문자를 포함하고 있는지 여부를 조사하도록 구현되었지만 하나만 제대로 작동한다. 어느 함수가 제대로 작동하는지 확인한 다음 그 이유를 설명하라. 또한 다른 두 함수가 적절하게 구현되지 않은 이유를 설명하라.

def any_lowercase1(text):
    for c in text:
        flag = c.islower()
    return flag

def any_lowercase2(text):
    for c in text:
        if not c.islower():
            return False
    return True

def any_lowercase3(text):
    flag = False
    for c in text:
        if c.islower():
            flag = True
    return flag

아래 문자열에 대해 위 함수를 테스트한다.

word1 = "ABcDE"
word2 = "ABCDE"

any_lowercase1() 함수

def any_lowercase1(text):
    for c in text:
        flag = c.islower()
    return flag

for c in text 반복문이 실행되는 동안 flag = c.islower()에 의해 계속해서 업데이트 된다. 따라서 마지막 문자의 소문자 여부가 최종적으로 반환된다. 즉, 문자열의 마지막 문자의 소문자 여부가 함수의 반환값으로 지정되어 word1, word2 모두에 대해 False가 반환된다.

any_lowercase1(word1)
False
any_lowercase1(word2)
False

any_lowercase2() 함수

def any_lowercase2(text):
    for c in text:
        if not c.islower():
            return False
    return True

for c in text 반복문이 실행되는 동안 if not c.islower() 에 의해 첫 문자가 소문자가 아닐 때, 즉 대문자이거나 알파벳이 아닌 다른 기호일 때 False를 바로 반환한다. 따라서 문자열 자체에 소문자가 포함되어 있다 하더라도 첫 문자가 소문자가 아니면 무조건 False가 반환된다.

any_lowercase2(word1)
False
any_lowercase2(word2)
False

any_lowercase3() 함수

def any_lowercase3(text):
    flag = False
    for c in text:
        if c.islower():
            flag = True
    return flag

flag 변수가 가리키는 값이 for c in text 반복문이 실행되는 동안 c가 소문자를 가리키는 순간 True로 지정된다. 반면에 text에 포함된 문자중에 소문자가 아니면 무시된다. 결국 소문자가 하나라도 포함된 경우에만 True가 반환된다.

any_lowercase3(word1)
True
any_lowercase3(word2)
False

결국 any_lowercase3() 만 소문자 포함여부를 제대로 결정한다.

문제 8

문자열 find() 메서드에 대응하는 find() 함수를 직접 정의하라. 단, 세 개의 매개변수를 사용하며 각 매개변수의 기능은 다음과 같아야 한다.

  • 매개 변수: 두 개의 문자열을 인자로 받는 word1word2 두 개와 키워드 인자를 받는 position.

  • word1word2를 부분 문자열로 포함할 경우 부분 문자열이 시작하는 인덱스 반환. 포함하지 않을 경우 -1을 반환.

  • position 매개변수: 탐색을 시작하는 인덱스 지정. 기본 키워드 인자로 0 사용.

단, 문자열 인덱싱, 슬라이싱만 사용하고 다른 문자열 메서드는 전혀 사용하지 않아야 한다.

힌트: range() 함수의 구간 변경

find() 함수의 헤더를 다음과 같이 지정한다.

def find(word1, word2, position=0)

find() 함수는 word1 문자열이 word2 문자열을 부분 문자열로 포함되는지 여부를 판단하기 위해 word1의 모든 인덱스에 대해 word2 부분 문자열과 일치 여부를 슬라이싱을 이용하여 확인하는 순간에 해당 인덱스를 반환한다. 또한 부분 문자열을 확인하지 못하면 -1을 반환한다.

position=0은 부분 문자열 탐색을 시작하는 인덱스를 가리키며 기본값으로 0을 사용한다. 즉, position 값을 지정하지 않거나 변경하지 않는다면 word1이 가리키는 문자열의 전 구간을 대상으로 부분 문자열 탐색 여부를 확인한다.

반면에 position 값을 0이 아닌 다른 값으로 지정하면 해당 인덱스부터 탐색을 시작한다. 이를 위해 range() 함수가 지정하는 아래처럼 구간을 position으로 시작하도록 한다.

range(position, len(word1))

find() 함수의 다른 부분은 동일하며, 정리하면 다음과 같다.

def find(word1, word2, position=0):
    for idx in range(position, len(word1)):
        if word2 == word1[idx:idx+len(word2)] :
            return idx
    return -1
  • position=0을 사용하는 경우

print(find('banana', 'ana'))
print(find('heyheyhey', 'ey'))
print(find('waikiki', 'ki'))
print(find('ulala', 'la'))
print(find('chukachuka', 'uKa'))
1
1
3
1
-1
  • position을 다르게 지정하는 경우

print(find('banana', 'ana', 2))
print(find('heyheyhey', 'ey', 3))
print(find('waikiki', 'ki', 4))
print(find('ulala', 'la', 2))
print(find('chukachuka', 'uKa'))
3
4
5
3
-1