파이썬 기초 강좌: 6. 문자열 예제와 실습 (Python Basics – String Examples and Exercises)

안녕하세요, 파이썬 기초 강좌에 오신 것을 환영합니다! 오늘은 파이썬 프로그래밍에서 가장 자주 사용되는 데이터 타입 중 하나인 문자열(strings)에 대해 알아보겠습니다. 문자열은 문자들의 집합으로, 다양한 방법으로 조작하고 변형할 수 있습니다. 이번 강좌에서는 문자열의 기본 개념부터 문자열을 처리하는 다양한 방법, 그리고 실전 예제를 통해 문자열을 효과적으로 사용하는 방법을 다뤄보겠습니다. 손코딩을 통해 파이썬 문자열의 매력을 직접 경험해 보세요! 그럼, 시작해봅시다.

파이썬 기초 강좌 - 문자열 예제와 실습

1. A string is a sequence

문자열은 문자들의 순서가 있는 모음입니다. 예를 들어, ‘banana’라는 단어는 ‘b’, ‘a’, ‘n’, ‘a’, ‘n’, ‘a’라는 문자들이 순서대로 나열된 것입니다. 각 문자는 위치를 가지고 있으며, 이 위치를 인덱스라고 합니다. 인덱스는 0부터 시작합니다.

  • sequence : An ordered set; that is, a set of values where each value is identified by an integer index
  • (실습)
>>> fruit = 'banana'
>>> letter = fruit[1]
>>> print(letter)
a

>>> letter = fruit[0]
>>> print(letter)
b

>>> letter = fruit[1.5]
TypeError: string indices must be integers
  • fruit[0]은 ‘banana’의 첫 번째 문자인 ‘b’를 의미합니다.
  • fruit[1]은 ‘banana’의 두 번째 문자인 ‘a’를 의미합니다.

2. Getting the length of a string using len

  • (실습)
>>> fruit = 'banana'
>>> len(fruit)
6

>>> length = len(fruit)
>>> last = fruit[length]
IndexError: string index out of range
# 왜 에러가 발생했는지 설명해 보세요

# 수정된 코드는 아래와 같습니다.
>>> last = fruit[length-1]
>>> print(last)
a

혹은
>>> last = fruit[-1]
>>> print(last) 
  • 왜 에러가 발생했는지 설명해 보세요

len 함수는 문자열의 길이를 반환합니다. ‘banana’라는 문자열의 길이는 6입니다. 그러나 문자열의 인덱스는 0부터 시작하므로, 마지막 문자의 인덱스는 길이에서 1을 뺀 5가 됩니다. 따라서 fruit[6]을 사용하면 문자열의 범위를 벗어나기 때문에 IndexError가 발생합니다.

  • 수정된 코드는 아래와 같습니다.
>>> last = fruit[length-1]
>>> print(last)
a

이 코드는 문자열의 길이에서 1을 뺀 인덱스를 사용하여 마지막 문자를 올바르게 참조합니다.

혹은

>>> last = fruit[-1]
>>> print(last)
a

이 코드는 음수 인덱스를 사용하여 문자열의 마지막 문자를 참조합니다. 파이썬에서는 음수 인덱스를 사용하여 문자열의 끝에서 부터 접근할 수 있습니다. -1은 마지막 문자를, -2는 마지막에서 두 번째 문자를 의미합니다.

이렇게 len 함수를 사용하면 문자열의 길이를 구할 수 있으며, 이를 통해 문자열의 마지막 문자에 올바르게 접근할 수 있습니다.

3. Traversal through a string with a loop

  • (실습)
fruit = "pineapple"

index = 0
while index < len(fruit):
    letter = fruit[index]
    print(letter)
    index = index + 1 # 짧게고치면 index += 1

이 코드는 while 루프를 사용하여 문자열 “pineapple”의 각 문자를 순회합니다. index 변수를 0으로 초기화한 후, 문자열의 길이(len(fruit))보다 작은 동안 반복됩니다. 각 반복에서 현재 인덱스에 해당하는 문자를 letter 변수에 저장하고, 이를 출력한 후 index를 1씩 증가시킵니다. index = index + 1 부분은 index += 1로 짧게 쓸 수 있습니다.

# 더 자주 사용되는 패턴
fruit = "pineapple"
for char in fruit:
    print(char)

for 루프는 문자열을 순회하는 더 간단하고 자주 사용되는 방법입니다. 이 예제에서는 for 루프를 사용하여 “pineapple” 문자열의 각 문자를 순회합니다. char 변수는 각 반복에서 문자열의 현재 문자를 나타내며, 이를 출력합니다.

  • 연습문제: 문자열의 마지막 문자에서 시작하여 첫 번째 문자로 거슬러 올라가면서 각 글자를 별도의 줄에 거꾸로 출력하는 while 루프를 작성하십시오.
fruit = "Watermelon"
index = ___________

while _________:
    print(fruit[index])
    index = __________
  • (정답)
fruit = "Watermelon"
index = len(fruit) - 1

while index >= 0:
    print(fruit[index])
    index = index - 1

4. String slices

  • (실습)
>>> s = 'Monty Python'
>>> print(s[0:5])
Monty
>>> print(s[6:12])
Python

슬라이싱은 문자열의 부분 문자열을 추출하는 방법입니다. s[0:5]는 문자열 s의 0번 인덱스부터 5번 인덱스 바로 앞까지의 부분 문자열을 추출합니다. 따라서 ‘Monty’가 출력됩니다. 마찬가지로, s[6:12]는 6번 인덱스부터 12번 인덱스 바로 앞까지의 부분 문자열을 추출하여 ‘Python’이 출력됩니다.

>>> fruit = 'banana'
>>> fruit[:3]
'ban'
>>> fruit[3:]
'ana'

슬라이싱은 시작 인덱스나 종료 인덱스를 생략할 수도 있습니다. fruit[:3]는 문자열 fruit의 처음부터 3번 인덱스 바로 앞까지의 부분 문자열을 추출합니다. 따라서 ‘ban’이 출력됩니다. 반대로, fruit[3:]는 3번 인덱스부터 문자열의 끝까지의 부분 문자열을 추출하여 ‘ana’가 출력됩니다.

>>> fruit = 'banana'
>>> fruit[3:3]
''

슬라이싱에서 시작 인덱스와 종료 인덱스가 같으면 빈 문자열을 반환합니다. fruit[3:3]는 3번 인덱스부터 3번 인덱스 바로 앞까지의 부분 문자열을 추출하려고 하지만, 시작과 종료가 같기 때문에 아무 문자도 포함되지 않아 빈 문자열이 반환됩니다.

  • 연습문제: fruit[:]는 무엇을 의미합니까?
  • (정답)
`fruit[:]`는 문자열 `fruit`의 전체 복사본을 의미합니다. 이 슬라이싱 구문은 문자열의 처음부터 끝까지 모든 문자를 포함하는 부분 문자열을 생성합니다.

5. Strings are immutable

  • (실습)
>>> greeting = 'Hello, world!'
>>> greeting[0] = 'J'
TypeError: 'str' object does not support item assignment

# 아래와 같이 해보세요.
>>> greeting = 'Hello, world!'
>>> new_greeting = 'J' + greeting[1:]
>>> print(new_greeting)
Jello, world!

문자열은 불변(immutable) 객체입니다. 이는 문자열을 생성한 후에 그 내용을 변경할 수 없다는 것을 의미합니다. 위의 코드에서 greeting[0] = 'J'와 같이 특정 인덱스의 문자를 변경하려고 하면 TypeError가 발생합니다.

6. Looping and counting

  • (실습)
# This program demonstrates another pattern of computation called a counter
word = 'banana'

count = 0
for letter in word:
    if letter == 'a':
        count = count + 1

print(count)

이 예제는 문자열에서 특정 문자의 빈도를 세는 방법을 보여줍니다.

  • word 변수에 ‘banana’가 저장됩니다.
  • count 변수를 0으로 초기화합니다.
  • for 루프를 사용하여 word의 각 문자를 순회합니다.
  • 각 문자가 ‘a’인지 확인하고, ‘a’인 경우 count를 1씩 증가시킵니다.
  • 루프가 끝난 후, ‘a’의 총 개수를 출력합니다. 이 예제에서는 ‘banana’에 ‘a’가 3번 등장하므로, 출력값은 3이 됩니다.

7. The in operator

  • (실습)
>>> 'a' in 'banana'
True
>>> 'seed' in 'banana'
False

# https://docs.python.org/3/library/stdtypes.html#string-methods
# str.find()의 Note 참고

in 연산자는 문자열 내에 특정 부분 문자열이 존재하는지 확인하는 데 사용됩니다.

  • 'a' in 'banana'는 ‘banana’에 ‘a’가 포함되어 있으므로 True를 반환합니다.
  • 'seed' in 'banana'는 ‘banana’에 ‘seed’가 포함되어 있지 않으므로 False를 반환합니다.

8. String comparison

  • (실습)
word = "Pineapple"

if word < 'banana':
    print('Your word, ' + word + ', comes before banana.')
elif word > 'banana':
    print('Your word, ' + word + ', comes after banana.')
else:
    print('All right, bananas.')

이 예제는 문자열 비교를 보여줍니다.

  • 문자열 word와 ‘banana’를 비교합니다.
  • 비교하는 각 문자를 순서대로 ASCII (또는 유니코드) 값을 기준으로 비교하게 됩니다.
  • word가 ‘banana’보다 ASCII 값이 적으면 첫 번째 메시지를, 크면 두 번째 메시지를 출력합니다.
  • 두 문자열이 같다면 마지막 메시지를 출력합니다.
char_A = 'A'
char_a = 'a'

ascii_value_A = ord(char_A)
ascii_value_a = ord(char_a)
print(f"The ASCII value of '{char_A}' is {ascii_value_A}")
print(f"The ASCII value of '{char_a}' is {ascii_value_a}")

이 예제는 ord() 함수를 사용하여 문자의 ASCII 값을 출력합니다.

  • ord(char_A)는 ‘A’의 ASCII 값을 반환합니다.
  • ord(char_a)는 ‘a’의 ASCII 값을 반환합니다.
  • 대문자 ‘A’와 소문자 ‘a’는 서로 다른 ASCII 값을 가지며, 대문자가 소문자보다 작은 값을 가집니다.

9. String methods

파이썬 문자열 메서드는 문자열을 조작하고 분석하는 데 유용한 여러 가지 기능을 제공합니다. 아래는 몇 가지 주요 문자열 메서드와 그 사용 예시입니다.

  • (실습)
>>> stuff = "oops"
>>> type(stuff)
<class 'str'>
>>> dir(stuff)
['__add__', '__class__', '__contains__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__getnewargs__', '__getstate__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__iter__', '__le__', '__len__', '__lt__', '__mod__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__rmod__', '__rmul__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'capitalize', 'casefold', 'center', 'count', 'encode', 'endswith', 'expandtabs', 'find', 'format', 'format_map', 'index', 'isalnum', 'isalpha', 'isascii', 'isdecimal', 'isdigit', 'isidentifier', 'islower', 'isnumeric', 'isprintable', 'isspace', 'istitle', 'isupper', 'join', 'ljust', 'lower', 'lstrip', 'maketrans', 'partition', 'removeprefix', 'removesuffix', 'replace', 'rfind', 'rindex', 'rjust', 'rpartition', 'rsplit', 'rstrip', 'split', 'splitlines', 'startswith', 'strip', 'swapcase', 'title', 'translate', 'upper', 'zfill']

>>> help(str.capitalize)
Help on method_descriptor:

capitalize(self, /)
    Return a capitalized version of the string.

    More specifically, make the first character have upper case and the rest lower
    case.
>>>

>>> stuff.capitalize()
'Oops'
>>> stuff
'oops'
>>> new_stuff = stuff.capitalize()
>>> new_stuff
'Oops'
>>>
  • type(stuff): 변수 stuff의 타입을 확인합니다. 여기서는 문자열(str) 타입입니다.
  • dir(stuff): 문자열 객체가 지원하는 모든 메서드와 속성을 나열합니다.
  • help(str.capitalize): capitalize 메서드에 대한 도움말을 제공합니다. 이 메서드는 문자열의 첫 문자를 대문자로 변환하고 나머지는 소문자로 변환합니다.
  • stuff.capitalize(): ‘oops’ 문자열의 첫 문자를 대문자로 변환하여 ‘Oops’를 반환합니다.
>>> word = 'banana'
>>> new_word = word.upper()
>>> print(new_word)
BANANA

>>> word = 'banana'
>>> index = word.find('a')
>>> print(index)
1
>>> word.find('na')
2
>>> word.find('na', 3)
4
  • word.upper(): 문자열을 모두 대문자로 변환합니다.
  • word.find('a'): 문자열에서 ‘a’의 첫 번째 위치를 찾습니다. 결과는 1입니다.
  • word.find('na'): 문자열에서 ‘na’의 첫 번째 위치를 찾습니다. 결과는 2입니다.
  • word.find('na', 3): 인덱스 3부터 시작하여 ‘na’의 위치를 찾습니다. 결과는 4입니다.
>>> line = ' Here we go\n\n\n\n\n\n\n '
>>> line.strip() # remove white space (spaces, tabs, or newlines)
'Here we go'
  • line.strip(): 문자열 양쪽 끝의 공백(스페이스, 탭, 또는 새 줄)을 제거합니다.
>>> line = 'Have a nice day'
>>> line.startswith('Have')
True
>>> line.startswith('h')
False
  • line.startswith('Have'): 문자열이 ‘Have’로 시작하는지 확인합니다.
  • line.startswith('h'): 문자열이 ‘h’로 시작하는지 확인합니다.
>>> line = 'Have a nice day'
>>> line.startswith('h')
False
>>> line.lower()
'have a nice day'
>>> line.lower().startswith('h')
True
  • line.lower(): 문자열을 모두 소문자로 변환합니다.
  • line.lower().startswith('h'): 소문자로 변환한 문자열이 ‘h’로 시작하는지 확인합니다.

10. Parsing strings

문자열 파싱을 해봅시다.

  • (실습)
>>> data = 'From john.doe@example.com Sat Jan 5 09:14:16 2023'
>>> atpos = data.find('@')
>>> print(atpos)
21
>>> sppos = data.find(' ',atpos)
>>> print(sppos)
31
>>> host = data[atpos+1:sppos]
>>> print(host)
'example.com'
>>>

이 예제는 이메일 주소에서 도메인 부분을 추출하는 방법을 보여줍니다.

  1. data.find('@')를 사용하여 ‘@’ 문자의 위치를 찾습니다.
  2. data.find(' ', atpos)를 사용하여 ‘@’ 이후 첫 번째 공백 문자의 위치를 찾습니다.
  3. 슬라이싱 data[atpos+1:sppos]를 사용하여 ‘@’ 다음 문자부터 공백 문자 바로 전까지의 부분 문자열을 추출합니다.

11. Formatted String Literals

포맷된 문자열 리터럴 활용법을 알아봅시다.

  • (실습)
>>> camels = 42
>>> f'{camels}'
'42'

>>> f'I have spotted {camels} camels.'
'I have spotted 42 camels.'

>>> years = 3
>>> count = .1
>>> species = 'camels'
>>> f'In {years} years I have spotted {count} {species}.'
'In 3 years I have spotted 0.1 camels.'

포맷된 문자열 리터럴(f-strings)은 문자열 내에 변수를 삽입하여 쉽게 값을 출력할 수 있는 방법입니다.

  1. f'{camels}': 변수 camels의 값을 문자열로 삽입합니다.
  2. f'I have spotted {camels} camels.': 문자열 내에 변수 camels의 값을 삽입합니다.
  3. f'In {years} years I have spotted {count} {species}.': 여러 변수를 문자열에 삽입합니다.

f-strings을 사용하면 {} 안에 변수나 표현식을 삽입하여 쉽게 가독성 높은 문자열을 만들 수 있습니다.

12. Debugging

  • (실습)
# 아래 코드는 empty 라인이 입력되면 라인3에서 IndexError가 발생합니다.
# IndexError가 발생하지 않도록 디버깅해서 라인3의 코드를 수정해보세요.
while True:
    line = input('> ')
    if line[0] == '#':
        continue
    if line == 'done':
        break
    print(line)

print('Done!')
  • (정답)
while True:
    line = input('> ')
    if len(line) > 0 and line[0] == '#':  # 수정된 부분
        continue
    if line == 'done':
        break
    print(line)

print('Done!')

이 예제는 사용자 입력을 처리하는 코드에서 발생할 수 있는 IndexError를 디버깅하는 방법을 보여줍니다.

원래 코드에서는 빈 문자열이 입력되면 line[0]을 참조할 때 IndexError가 발생합니다. 이를 방지하기 위해, 문자열의 첫 번째 문자를 확인하기 전에 문자열이 비어 있지 않은지 확인합니다.

수정된 코드:

  • if len(line) > 0 and line[0] == '#':를 사용하여, 문자열의 길이가 0보다 클 때만 첫 번째 문자를 확인합니다.
  • 빈 문자열이 입력되면 line[0]을 참조하지 않으므로 IndexError가 발생하지 않습니다.

이렇게 하면 빈 문자열이 입력되었을 때도 프로그램이 정상적으로 작동합니다.

Exercise

  • (1) 아래 URL에 접속해서 string methods를 리뷰 하세요
https://docs.python.org/3/library/stdtypes.html#string-methods

Leave a Comment