Python & AI Tutorials Logo
Python 프로그래밍

5. 문자열을 사용해 텍스트 다루기

프로그래밍에서 텍스트는 어디에나 있습니다. 사용자에게 메시지를 보여 주는 일부터, 데이터 파일을 처리하고, 웹 애플리케이션을 만드는 것까지, 텍스트를 다루는 일은 프로그래머로서 개발하게 될 가장 기본적인 기술 중 하나입니다. Python에서는 문자열(string) 을 사용해 텍스트를 다룹니다. 문자열은 단어, 문장, 또는 어떤 형태의 텍스트 데이터든 나타낼 수 있는 문자들의 시퀀스입니다.

이미 이전 장에서 print()input() 을 사용할 때 문자열을 간단히 접해 보았습니다. 이제 문자열을 깊이 있게 살펴보면서, 문자열을 만드는 방법, 조작하는 방법, 그리고 Python이 제공하는 강력한 내장 문자열 기능을 이용해 실제 텍스트 처리 문제를 해결하는 방법을 배웁니다.

이 장에서는 특수 문자가 포함된 문자열을 만드는 방법, 문자열을 서로 결합하는 방법, 문자열의 일부만 추출하는 방법, 문자열의 대소문자와 서식을 바꾸는 방법, 문자열 안에서 텍스트를 검색하는 방법, 그리고 수정과 관련해서 문자열이 숫자와 다르게 동작하는 이유를 배우게 됩니다. 장을 마치면 Python에서 텍스트를 다루는 데 탄탄한 기초를 갖추게 될 것입니다.

5.1) 문자열 리터럴과 이스케이프 시퀀스

5.1.1) 문자열 리터럴 만들기

문자열 리터럴(string literal) 은 코드 안에 직접 작성한 문자열 값입니다. 이미 작은따옴표(')나 큰따옴표(")를 사용해 문자열을 만든 예를 봤습니다:

python
# string_basics.py
greeting = 'Hello, World!'
message = "Python is great!"
 
print(greeting)  # Output: Hello, World!
print(message)   # Output: Python is great!

작은따옴표와 큰따옴표는 Python에서 완전히 동일하게 동작합니다. 어떤 것을 쓸지는 여러분의 선택입니다. 다만 문자열 안에 따옴표 문자가 들어갈 때 이 두 가지 선택지가 있다는 점이 유용합니다:

python
# quotes_in_strings.py
# 문자열 안에 작은따옴표가 있을 때는 큰따옴표 사용
sentence = "It's a beautiful day!"
print(sentence)  # Output: It's a beautiful day!
 
# 문자열 안에 큰따옴표가 있을 때는 작은따옴표 사용
quote = 'She said, "Hello!"'
print(quote)  # Output: She said, "Hello!"

문자열을 둘러싸는 따옴표와 같은 종류의 따옴표를 문자열 안에 넣어야 한다면, 백슬래시(\)로 이스케이프(escape) 할 수 있습니다:

python
# escaping_quotes.py
# 작은따옴표로 둘러싸인 문자열 안에서 작은따옴표 이스케이프하기
sentence = 'It\'s a beautiful day!'
print(sentence)  # Output: It's a beautiful day!
 
# 큰따옴표로 둘러싸인 문자열 안에서 큰따옴표 이스케이프하기
quote = "She said, \"Hello!\""
print(quote)  # Output: She said, "Hello!"

백슬래시는 Python에 다음에 오는 따옴표가 문자열의 끝이 아니라, 문자열 내용의 일부라는 것을 알려 줍니다.

5.1.2) 삼중 따옴표를 사용한 여러 줄 문자열

여러 줄에 걸친 문자열이 필요할 때, Python은 삼중 따옴표(triple quotes) 를 제공합니다. 작은따옴표 세 개(''')나 큰따옴표 세 개(""")를 사용할 수 있습니다:

python
# multiline_strings.py
poem = """Roses are red,
Violets are blue,
Python is awesome,
And so are you!"""
 
print(poem)
# Output:
# Roses are red,
# Violets are blue,
# Python is awesome,
# And so are you!

삼중 따옴표 문자열은 여러분이 입력한 대로 줄바꿈과 공백을 그대로 유지합니다. 긴 텍스트 블록, 문서화 문자열(docstring, 19장에서 살펴봅니다), 또는 이스케이프 없이 작은따옴표와 큰따옴표를 모두 포함해야 할 때 특히 유용합니다:

python
# triple_quotes_convenience.py
dialogue = '''The teacher said, "Don't forget: it's important to practice!"'''
print(dialogue)  # Output: The teacher said, "Don't forget: it's important to practice!"

5.1.3) 흔히 사용하는 이스케이프 시퀀스

따옴표를 이스케이프하는 것 외에도, 백슬래시는 이스케이프 시퀀스(escape sequence) 를 도입합니다. 이는 직접 입력하기 어렵거나 불가능한 문자를 나타내는 특수한 두 글자 조합입니다:

python
# escape_sequences.py
# 새 줄: 다음 줄로 이동
print("First line\nSecond line")
# Output:
# First line
# Second line
 
# 탭: 가로 방향의 간격을 삽입
print("Name:\tJohn\nAge:\t25")
# Output:
# Name:	John
# Age:	25
 
# 백슬래시 자체를 포함하기
path = "C:\\Users\\Documents"
print(path)  # Output: C:\Users\Documents

가장 많이 사용하는 이스케이프 시퀀스는 다음과 같습니다:

Escape Sequence의미예시 출력
\n새 줄 (줄바꿈)두 줄
\t탭 (가로 간격)들여쓴 텍스트
\\백슬래시\ 문자
\'작은따옴표' 문자
\"큰따옴표" 문자

이스케이프 시퀀스를 이해하는 것은 파일 경로(특히 백슬래시를 사용하는 Windows에서), 서식 있는 출력, 또는 특수한 형식이 필요한 텍스트를 다룰 때 매우 중요합니다.

5.1.4) 백슬래시를 그대로 쓰기 위한 raw 문자열

때로는 이스케이프 시퀀스를 사용하지 않고, 백슬래시를 그대로 문자로 취급하고 싶을 때가 있습니다. 이는 파일 경로나 정규 표현식(regular expression, 39장에서 간단히 다룹니다)을 다룰 때 흔합니다. Python은 문자열 앞에 r 을 붙여 raw 문자열(raw string) 을 제공합니다:

python
# raw_strings.py
# 일반 문자열: 백슬래시는 이스케이프 시퀀스를 유발
regular = "C:\new\test"
print(regular)  # Output: C:
                #         ew   est
                # (\n은 새 줄, \t는 탭이 됨)
 
# raw 문자열: 백슬래시를 있는 그대로 사용
raw = r"C:\new\test"
print(raw)  # Output: C:\new\test

raw 문자열에서 \n 은 새 줄이 아니라, 백슬래시와 n 이라는 두 문자 그대로입니다. raw 문자열은 Windows 파일 경로에서 특히 유용합니다:

python
# windows_paths.py
# raw 문자열이 아니면, 모든 백슬래시를 이스케이프해야 함
path1 = "C:\\Users\\John\\Documents\\file.txt"
 
# raw 문자열을 사용하면 백슬래시를 자연스럽게 쓸 수 있음
path2 = r"C:\Users\John\Documents\file.txt"
 
print(path1)  # Output: C:\Users\John\Documents\file.txt
print(path2)  # Output: C:\Users\John\Documents\file.txt

두 방식 모두 같은 결과를 내지만, 백슬래시가 많을 때는 raw 문자열이 더 읽기 좋습니다.

5.2) 문자열 이어 붙이기와 반복

5.2.1) + 로 문자열 이어 붙이기

+ 연산자를 사용해 문자열을 서로 결합할 수 있습니다. 이를 이어 붙이기(concatenation) 라고 부릅니다:

python
# string_concatenation.py
first_name = "John"
last_name = "Smith"
 
# + 로 문자열 결합하기
full_name = first_name + " " + last_name
print(full_name)  # Output: John Smith
 
# 더 긴 문자열 만들기
greeting = "Hello, " + full_name + "!"
print(greeting)  # Output: Hello, John Smith!

이어 붙이기는 문자열들을 끝에서 끝으로 이어 붙여 새로운 문자열을 만듭니다. Python이 자동으로 공백을 넣어 주지 않는다는 점에 주의해야 합니다. 공백은 직접 넣어야 합니다:

python
# concatenation_spacing.py
word1 = "Hello"
word2 = "World"
 
# 공백 없이
no_space = word1 + word2
print(no_space)  # Output: HelloWorld
 
# 공백 포함
with_space = word1 + " " + word2
print(with_space)  # Output: Hello World

하나의 표현식에서 원하는 만큼 문자열을 이어 붙일 수 있습니다:

python
# multiple_concatenation.py
address = "123" + " " + "Main" + " " + "Street"
print(address)  # Output: 123 Main Street

중요한 제한사항: 문자열은 다른 문자열과만 이어 붙일 수 있습니다. 문자열과 숫자를 그대로 이어 붙이면 에러가 발생합니다:

python
# concatenation_error.py
age = 25
# 이것은 에러를 발생시킵니다:
# message = "I am " + age + " years old"  # TypeError!
 
# 숫자를 먼저 문자열로 변환해야 합니다
message = "I am " + str(age) + " years old"
print(message)  # Output: I am 25 years old

문자열과 숫자 변환에 대해서는 5.6절에서 더 자세히 살펴봅니다.

5.2.2) * 로 문자열 반복하기

Python에서는 * 연산자를 사용해 문자열을 여러 번 반복하는 편리한 기능을 제공합니다:

python
# string_repetition.py
separator = "-" * 20
print(separator)  # Output: --------------------
 
# 패턴 만들기
pattern = "abc" * 3
print(pattern)  # Output: abcabcabc
 
# 출력 서식 지정에 유용
print("=" * 30)
print("Important Message")
print("=" * 30)
# Output:
# ==============================
# Important Message
# ==============================

반복 연산자는 어떤 양의 정수와도 함께 사용할 수 있습니다:

python
# repetition_examples.py
# 0번 반복하면 빈 문자열이 됩니다
nothing = "Hello" * 0
print(nothing)      # Output: (empty string)
print(len(nothing)) # Output: 0
 
# 1번 반복은 원래 문자열과 같습니다
once = "Hello" * 1
print(once)  # Output: Hello
 
# 더 큰 반복
many = "Go! " * 5
print(many)  # Output: Go! Go! Go! Go! Go!

문자열 반복은 시각적인 구분선 만들기, 패딩(padding) 추가, 또는 테스트 데이터를 생성하는 데 특히 유용합니다:

python
# practical_repetition.py
# 간단한 텍스트 박스 만들기
width = 40
border = "=" * width
title = "Welcome"
padding = " " * ((width - len(title)) // 2)
 
print(border)
print(padding + title)
print(border)
# Output:
# ========================================
#                 Welcome
# ========================================

5.2.3) 이어 붙이기와 반복 결합하기

숫자 연산에서와 마찬가지로, 두 연산자는 같은 표현식 안에서 결합해 사용할 수 있으며, Python의 연산자 우선순위 규칙(곱셈이 덧셈보다 먼저)을 따릅니다:

python
# combined_operations.py
# 먼저 반복이 수행되고, 그 다음 이어 붙이기
result = "=" * 10 + " Title " + "=" * 10
print(result)  # Output: ========== Title ==========
 
# 괄호를 사용해 순서를 제어
repeated_phrase = ("Hello " + "World ") * 3
print(repeated_phrase)  # Output: Hello World Hello World Hello World

이러한 연산들은 문자열 조작의 기초를 이루며, 간단한 조각들로부터 복잡한 문자열을 만드는 데 사용됩니다.

5.3) 문자열 인덱싱과 슬라이싱

Python에서 문자열은 문자들의 시퀀스(sequence) 이기 때문에, 각 문자는 고유한 위치를 가집니다. 인덱싱과 슬라이싱을 사용해 개별 문자를 읽거나 문자열의 일부를 추출할 수 있습니다.

5.3.1) 문자열 인덱스 이해하기

문자열의 각 문자는 인덱스(index) 라는 숫자 위치를 가집니다. Python은 0부터 시작하는 인덱싱(zero-based indexing) 을 사용하므로, 첫 번째 문자는 인덱스 0, 두 번째 문자는 인덱스 1, 이런 식으로 계속됩니다:

python
# string_indexing.py
text = "Python"
 
# 인덱스로 개별 문자 접근하기
print(text[0])  # Output: P (첫 번째 문자)
print(text[1])  # Output: y (두 번째 문자)
print(text[5])  # Output: n (여섯 번째 문자)

인덱스와 문자가 어떻게 대응되는지 시각적으로 나타내면 다음과 같습니다:

String:  P  y  t  h  o  n
Index:   0  1  2  3  4  5

Python은 문자열 끝에서부터 세는 음수 인덱스(negative index) 도 지원합니다. 인덱스 -1 은 마지막 문자를, -2 는 끝에서 두 번째 문자를 가리키는 식입니다:

python
# negative_indexing.py
text = "Python"
 
print(text[-1])  # Output: n (마지막 문자)
print(text[-2])  # Output: o (끝에서 두 번째)
print(text[-6])  # Output: P (첫 번째 문자)

음수 인덱스는 문자열의 정확한 길이를 몰라도, 문자열 끝 근처의 문자에 접근하고 싶을 때 특히 유용합니다:

String:    P  y  t  h  o  n
Positive:  0  1  2  3  4  5
Negative: -6 -5 -4 -3 -2 -1

String: 'Python'

양의 인덱싱

음의 인덱싱

[0] = 'P'
[1] = 'y'
[2] = 't'
[3] = 'h'
[4] = 'o'
[5] = 'n'

[-6] = 'P'
[-5] = 'y'
[-4] = 't'
[-3] = 'h'
[-2] = 'o'
[-1] = 'n'

중요: 존재하지 않는 인덱스에 접근하려 하면 IndexError 가 발생합니다:

python
# index_error.py
text = "Python"
 
# 이것은 문제없음
print(text[5])  # Output: n
 
# 인덱스 6은 존재하지 않기 때문에 에러 발생
# print(text[6])  # IndexError: string index out of range

5.3.2) 슬라이싱으로 부분 문자열 추출하기

인덱싱은 한 글자만 가져오지만, 슬라이싱(slicing) 을 사용하면 문자열의 일부(이를 부분 문자열(substring) 이라고 부릅니다)를 추출할 수 있습니다. 기본 문법은 다음과 같습니다:

string[start:stop]

이는 인덱스 start 부터 stop 직전까지 의 문자를 추출합니다:

python
# basic_slicing.py
text = "Python Programming"
 
# 인덱스 0부터 6 직전까지 추출
print(text[0:6])  # Output: Python
 
# 인덱스 7부터 18 직전까지 추출
print(text[7:18])  # Output: Programming
 
# 중간 부분 추출
print(text[7:11])  # Output: Prog

여기서 중요한 점은 stop 인덱스는 결과에 포함되지 않는다 는 것입니다. 인덱스를 문자들 사이를 가리키는 위치로 생각하면 이해하기 쉽습니다:

 P  y  t  h  o  n
 0  1  2  3  4  5  6

따라서 text[0:6] 은 "0 위치에서 시작해 6 위치 직전에서 멈춘다"는 뜻이고, 인덱스 0, 1, 2, 3, 4, 5 위치의 문자를 가져옵니다.

5.3.3) 시작 또는 끝 인덱스 생략하기

start 인덱스를 생략해 처음부터 슬라이스하거나, stop 인덱스를 생략해 끝까지 슬라이스할 수 있습니다:

python
# omitting_indices.py
text = "Python Programming"
 
# 처음부터 인덱스 6 직전까지
print(text[:6])  # Output: Python
 
# 인덱스 7부터 끝까지
print(text[7:])  # Output: Programming
 
# 전체 문자열 (처음부터 끝까지)
print(text[:])  # Output: Python Programming

이러한 단축 표기는 Python 코드에서 매우 흔하게 사용됩니다. 의도를 분명히 보여 주고, 길이를 하드코딩하지 않아도 되기 때문입니다.

5.3.4) 슬라이스에서 음수 인덱스 사용하기

슬라이스에서도 음수 인덱스를 사용할 수 있어, 끝에서부터 셀 수 있습니다:

python
# negative_slice_indices.py
text = "Python Programming"
 
# 마지막 11글자
print(text[-11:])  # Output: Programming
 
# 마지막 11글자를 제외한 나머지
print(text[:-11])  # Output: Python
 
# 마지막 7글자
print(text[-7:])  # Output: ramming
 
# 인덱스 7부터 끝에서 세 번째 글자 직전까지
print(text[7:-3])  # Output: Programm (마지막 'ing' 직전에서 멈춤)

음수 인덱스는 문자열 끝에서 일정 개수의 문자를 제외하고 싶을 때 특히 유용합니다:

python
# removing_suffix.py
filename = "document.txt"
 
# 마지막 4글자(.txt)를 제외한 모든 부분 얻기
name_without_extension = filename[:-4]
print(name_without_extension)  # Output: document

5.3.5) step 값을 사용한 슬라이싱

슬라이스에는 세 번째 값인 step 을 포함할 수 있습니다. 이는 몇 글자마다 한 번씩 건너뛸지 결정합니다:

string[start:stop:step]
python
# slicing_with_step.py
text = "Python Programming"
 
# 문자열 전체에서 한 글자마다 하나씩 건너뛰기 (2글자 간격)
print(text[::2])  # Output: Pto rgamn
 
# 인덱스 0부터 6 직전까지 2글자 간격
print(text[0:6:2])  # Output: Pto
 
# 3글자 간격
print(text[::3])  # Output: Ph oai

특히 유용한 트릭 하나는 step 을 -1 로 사용해 문자열을 뒤집는 것입니다:

python
# reversing_strings.py
text = "Python"
 
# 전체 문자열 뒤집기
reversed_text = text[::-1]
print(reversed_text)  # Output: nohtyP
 
# 실용 예: 회문(palindrome) 검사
word = "radar"
if word == word[::-1]:
    print(f"{word} is a palindrome!")  # Output: radar is a palindrome!

5.3.6) 슬라이싱은 에러를 일으키지 않는다

인덱싱과 달리, 슬라이싱은 매우 관대합니다. 범위를 벗어난 인덱스를 지정해도, Python이 자동으로 유효한 범위 안으로 조정해 줍니다:

python
# safe_slicing.py
text = "Python"
 
# 모두 에러 없이 동작
print(text[0:100])   # Output: Python (끝에서 멈춤)
print(text[10:20])   # Output: (빈 문자열 - 시작이 끝보다 뒤)
print(text[-100:3])  # Output: Pyt (시작이 0으로 조정됨)

이러한 동작 덕분에 문자열 길이를 정확히 모를 때도 슬라이싱을 안심하고 사용할 수 있습니다.

5.3.7) 실용적인 슬라이싱 예제

자주 사용하게 될 몇 가지 패턴은 다음과 같습니다:

python
# practical_slicing.py
text = "Hello, World!"
 
# 앞 5글자
print(text[:5])  # Output: Hello
 
# 마지막 6글자
print(text[-6:])  # Output: World!
 
# 첫 글자와 마지막 글자를 제외한 모든 글자
print(text[1:-1])  # Output: ello, World
 
# 한 글자씩 건너뛰기
print(text[::2])  # Output: Hlo ol!
 
# 문자열 뒤집기
print(text[::-1])  # Output: !dlroW ,olleH

인덱싱과 슬라이싱을 이해하는 것은 Python에서 텍스트를 처리하는 데 기본이 됩니다. 이 기술은 앞으로의 프로그래밍 여정 내내 반복해서 등장할 것입니다.

5.4) 대소문자와 공백을 위한 대표적인 문자열 메서드

Python 문자열에는 많은 내장 메서드(method) 가 있습니다. 메서드는 문자열 객체에 붙어 있고, 그 문자열에 대해 어떤 동작을 수행하는 함수입니다. 이 절에서는 텍스트를 정리하고 서식을 맞출 때 필수적인 대소문자 변경과 공백 처리 메서드를 살펴보겠습니다.

5.4.1) 문자열 메서드 이해하기

메서드(method)string.method_name() 처럼 점(dot) 표기법으로 호출합니다. 메서드는 특정 타입의 객체에 속한 함수입니다. 문자열에 대해서는 Python이 수십 가지 유용한 메서드를 제공합니다:

python
# method_basics.py
text = "hello"
 
# 문자열에서 메서드 호출하기
result = text.upper()
print(result)  # Output: HELLO
 
# 원래 문자열은 변경되지 않습니다 (이에 대해서는 5.8절에서 설명합니다)
print(text)  # Output: hello

각 메서드는 새로운 문자열을 반환하기 때문에, 메서드를 연쇄적으로 호출(chaining)할 수 있습니다:

python
# method_chaining.py
text = "  hello world  "
 
# 여러 메서드 연쇄 호출
result = text.strip().upper().replace("WORLD", "PYTHON")
print(result)  # Output: HELLO PYTHON

5.4.2) 대소문자 변환 메서드

Python은 문자열의 대소문자를 변경하는 여러 메서드를 제공합니다:

python
# case_methods.py
text = "Python Programming"
 
# 모두 대문자로 변환
print(text.upper())  # Output: PYTHON PROGRAMMING
 
# 모두 소문자로 변환
print(text.lower())  # Output: python programming
 
# 첫 글자만 대문자, 나머지는 소문자
print(text.capitalize())  # Output: Python programming
 
# 각 단어의 첫 글자를 대문자로
print(text.title())  # Output: Python Programming

이 메서드들은 사용자 입력을 표준화할 때 특히 유용합니다:

python
# case_normalization.py
# 사용자 입력을 흉내 냄
user_input = "YES"
 
# 대소문자에 상관없는 비교
if user_input.lower() == "yes":
    print("User confirmed!")  # Output: User confirmed!
 
# 또 다른 방식: upper() 사용
command = "start"
if command.upper() == "START":
    print("Starting process...")  # Output: Starting process...

title() 메서드 는 각 단어의 첫 글자를 대문자로 만들어, 이름이나 제목을 서식화할 때 유용합니다:

python
# title_case.py
name = "john smith"
print(name.title())  # Output: John Smith
 
book = "the great gatsby"
print(book.title())  # Output: The Great Gatsby

하지만 title() 은 작은따옴표나 특수한 경우에 한계가 있습니다:

python
# title_limitations.py
text = "it's a beautiful day"
print(text.title())  # Output: It'S A Beautiful Day (S에 대문자 주의)
 
# 더 정교한 제목 표기는 별도의 로직이 필요할 수 있습니다

capitalize() 메서드 는 문자열 전체 중 맨 앞 글자만 대문자로 만듭니다:

python
# capitalize_examples.py
sentence = "python is great"
print(sentence.capitalize())  # Output: Python is great
 
# 주의: 첫 글자만 대문자
multi_word = "hello world"
print(multi_word.capitalize())  # Output: Hello world (Hello World가 아님)

5.4.3) 대소문자 검사 메서드

Python에는 문자열의 대소문자를 검사하는 메서드들도 있습니다:

python
# case_checking.py
text1 = "HELLO"
text2 = "hello"
text3 = "Hello World"
 
# 모든 문자가 대문자인지 확인
print(text1.isupper())  # Output: True
print(text2.isupper())  # Output: False
 
# 모든 문자가 소문자인지 확인
print(text1.islower())  # Output: False
print(text2.islower())  # Output: True
 
# 문자열이 title case 인지 확인
print(text3.istitle())  # Output: True
print(text2.istitle())  # Output: False

이 검사 메서드는 True 또는 False (3장에서 배운 불리언(Boolean) 값)를 반환하기 때문에 조건문에 쓰기 좋습니다:

python
# case_checking_conditions.py
password = "SECRET123"
 
if password.isupper():
    print("Password is all uppercase")  # Output: Password is all uppercase

5.4.4) 공백 제거 메서드

공백(whitespace) 은 공백 문자(space), 탭(\t), 새 줄(\n)을 포함합니다. Python은 문자열의 양쪽 끝에서 공백을 제거하는 메서드를 제공합니다:

python
# whitespace_removal.py
text = "   Hello, World!   "
 
# 양쪽 끝의 공백 제거
print(text.strip())  # Output: Hello, World!
 
# 왼쪽(시작 부분)의 공백 제거
print(text.lstrip())  # Output: Hello, World!   
 
# 오른쪽(끝 부분)의 공백 제거
print(text.rstrip())  # Output:    Hello, World!

strip() 메서드는 사용자 입력을 정리(cleaning)할 때 매우 유용합니다:

python
# cleaning_input.py
# 여분의 공백이 있는 사용자 입력을 흉내 냄
user_name = "  John Smith  "
 
# 입력 정리
clean_name = user_name.strip()
print(f"Welcome, {clean_name}!")  # Output: Welcome, John Smith!

이 메서드들은 탭과 새 줄도 제거합니다:

python
# strip_all_whitespace.py
text = "\n\t  Hello  \t\n"
print(repr(text))  # Output: '\n\t  Hello  \t\n'
 
cleaned = text.strip()
print(repr(cleaned))  # Output: 'Hello'

단, strip(), lstrip(), rstrip() 은 문자열의 양 끝에서만 공백을 제거하고, 가운데에 있는 공백은 건드리지 않습니다:

python
# strip_edges_only.py
text = "  Hello   World  "
print(text.strip())  # Output: Hello   World (중간의 공백은 그대로)

5.4.5) 특정 문자 제거하기

strip 계열 메서드는 공백뿐 아니라, 특정 문자들을 제거하는 용도로도 사용할 수 있습니다:

python
# 여러 다른 문자 제거하기
text = "...Hello!!!"
cleaned = text.strip(".!")
print(cleaned)  # Output: Hello

strip() 에 문자열을 전달하면, 그 문자열에 포함된 문자들의 어떤 조합이든 양 끝에서 제거합니다:

python
# strip_character_set.py
text = "xxxyyyHelloyyyxxx"
 
# 양끝에서 x 또는 y 를 모두 제거
result = text.strip("xy")
print(result)  # Output: Hello

5.4.6) 대소문자·공백 메서드를 결합한 실용 예제

이 메서드들이 매우 유용한 실제 상황은 다음과 같습니다:

python
# practical_text_cleaning.py
# 사용자 입력 정리 및 표준화
user_email = "  JohnSmith@EXAMPLE.com  "
clean_email = user_email.strip().lower()
print(clean_email)  # Output: johnsmith@example.com
 
# 이름을 올바른 형식으로 만들기
raw_name = "  john smith  "
formatted_name = raw_name.strip().title()
print(formatted_name)  # Output: John Smith
 
# 명령 처리 (대소문자 무시)
command = "  START  "
if command.strip().upper() == "START":
    print("Command recognized!")  # Output: Command recognized!

이 메서드들은 텍스트 정리(cleaning)와 정규화(normalization)의 기초를 이룹니다. 사용자 입력을 처리하거나, 파일을 읽거나, 분석을 위한 데이터를 준비할 때 끊임없이 사용하게 될 것입니다.

5.5) 문자열에서 검색하고 교체하기

문자열 안에서 텍스트를 찾고 수정하는 작업은 프로그래밍에서 매우 흔합니다. Python은 부분 문자열을 검색하고 텍스트를 교체하기 위한 강력한 메서드를 제공합니다.

5.5.1) find()와 index()로 부분 문자열 찾기

find() 메서드는 부분 문자열을 검색하고, 처음 등장하는 위치의 인덱스를 반환합니다:

python
# find_method.py
text = "Python is great. Python is powerful."
 
# "Python" 이 처음 나타나는 위치 찾기
position = text.find("Python")
print(position)  # Output: 0 (문자열의 시작 위치)
 
# "great" 찾기
position = text.find("great")
print(position)  # Output: 10
 
# 존재하지 않는 문자열 찾기
position = text.find("Java")
print(position)  # Output: -1 (찾지 못함)

find() 메서드는 부분 문자열을 찾지 못하면 -1 을 반환하므로, 에러를 일으키지 않고 안전하게 사용할 수 있습니다:

python
# safe_searching.py
text = "Hello, World!"
 
# 부분 문자열이 존재하는지 확인
if text.find("World") != -1:
    print("Found 'World'!")  # Output: Found 'World'!
 
if text.find("Python") == -1:
    print("'Python' not found")  # Output: 'Python' not found

또한 특정 위치부터 검색을 시작할 수도 있습니다:

python
# find_with_start.py
text = "Python is great. Python is powerful."
 
# 첫 번째 등장 위치
first = text.find("Python")
print(first)  # Output: 0
 
# 첫 번째 이후 위치에서 다음 "Python" 찾기
second = text.find("Python", first + 1)
print(second)  # Output: 17

index() 메서드는 find() 와 비슷하게 동작하지만, 부분 문자열을 찾지 못하면 에러를 발생시킵니다:

python
# index_method.py
text = "Hello, World!"
 
# 이 호출은 문제없음
position = text.index("World")
print(position)  # Output: 7
 
# 이것은 ValueError 를 발생시킵니다:
# position = text.index("Python")  # ValueError: substring not found

어떤 것을 언제 사용할까?

  • 부분 문자열이 있는지 확인하고 싶을 때는 find() 사용 (-1 을 반환하므로 안전)
  • 부분 문자열이 반드시 존재한다고 확신할 때는 index() 사용 (못 찾으면 에러 발생)
python
# choosing_find_vs_index.py
text = "Python Programming"
 
# 안전한 확인을 위해 find() 사용
if text.find("Java") != -1:
    print("Found Java")
else:
    print("Java not found")  # Output: Java not found
 
# 반드시 존재한다고 알 때는 index() 사용
position = text.index("Python")  # Python 이 있다는 것을 알고 있음
print(f"Found at position {position}")  # Output: Found at position 0

5.5.2) rfind()와 rindex()로 뒤에서부터 찾기

rfind()rindex() 메서드는 문자열의 오른쪽(끝)에서부터 검색합니다:

python
# rfind_method.py
text = "Python is great. Python is powerful."
 
# "Python" 의 마지막 등장 위치 찾기
last_position = text.rfind("Python")
print(last_position)  # Output: 17
 
# find() 는 첫 번째 등장 위치를 반환
first_position = text.find("Python")
print(first_position)  # Output: 0

마지막으로 등장하는 위치가 필요할 때 유용합니다:

python
# last_occurrence.py
filename = "document.backup.txt"
 
# 마지막 점(.) 찾기 (파일 확장자 얻기)
last_dot = filename.rfind(".")
if last_dot != -1:
    extension = filename[last_dot:]
    print(extension)  # Output: .txt

5.5.3) count() 로 등장 횟수 세기

count() 메서드는 부분 문자열이 몇 번 등장하는지 알려 줍니다:

python
# count_method.py
text = "Python is great. Python is powerful. Python is fun."
 
# "Python" 이 몇 번 등장하는지 세기
count = text.count("Python")
print(count)  # Output: 3
 
# 문자 하나를 세기
letter_count = text.count("o")
print(f"Letter 'o' appears {letter_count} times")  # Output: Letter 'o' appears 4 times

특정 범위 안에서만 세는 것도 가능합니다:

python
# count_in_range.py
text = "abcabcabc"
 
# 전체 문자열에서 "abc" 세기
total = text.count("abc")
print(total)  # Output: 3
 
# 처음 6글자에서만 "abc" 세기
partial = text.count("abc", 0, 6)
print(partial)  # Output: 2

5.5.4) replace() 로 텍스트 교체하기

replace() 메서드는 모든 부분 문자열을 다른 문자열로 교체한 새로운 문자열을 만듭니다:

python
# replace_method.py
text = "I love Java. Java is great."
 
# 모든 "Java" 를 "Python" 으로 교체
new_text = text.replace("Java", "Python")
print(new_text)  # Output: I love Python. Python is great.
 
# 원래 문자열은 변경되지 않음
print(text)  # Output: I love Java. Java is great.

세 번째 인자로 교체 횟수에 제한을 둘 수 있습니다:

python
# limited_replace.py
text = "one one one one"
 
# 처음 2번만 교체
result = text.replace("one", "two", 2)
print(result)  # Output: two two one one

replace() 메서드는 대소문자를 구분합니다:

python
# case_sensitive_replace.py
text = "Python is great. python is powerful."
 
# 대문자 P인 "Python" 만 교체
result = text.replace("Python", "Java")
print(result)  # Output: Java is great. python is powerful.

대소문자를 구분하지 않고 교체하려면 수동으로 처리해야 합니다:

python
# case_insensitive_approach.py
text = "Python is great. python is powerful."
 
# 모두 소문자로 바꾼 뒤 교체하면, 원래의 대소문자 정보는 사라짐
result = text.lower().replace("python", "java")
print(result)  # Output: java is great. java is powerful.

5.5.5) 실용적인 검색·교체 예제

이 메서드들이 빛을 발하는 실제 상황은 다음과 같습니다:

python
# practical_search_replace.py
# 데이터 정리: 불필요한 문자 제거
phone = "123-456-7890"
clean_phone = phone.replace("-", "")
print(clean_phone)  # Output: 1234567890
 
# 단어 가리기(검열)
message = "This is a bad word and another bad word."
censored = message.replace("bad", "***")
print(censored)  # Output: This is a *** word and another *** word.
 
# 파일 확장자 추출
filename = "document.txt"
dot_position = filename.rfind(".")
if dot_position != -1:
    extension = filename[dot_position + 1:]
    print(f"File type: {extension}")  # Output: File type: txt
 
# 단어 등장 횟수 세기(단순한 방법)
text = "Python is fun. I love Python. Python rocks!"
word = "Python"
occurrences = text.count(word)
print(f"'{word}' appears {occurrences} times")  # Output: 'Python' appears 3 times

find

rfind

count

replace

String: 'Hello World Hello'

검색 연산

find('Hello')
결과: 0

rfind('Hello')
결과: 12

count('Hello')
결과: 2

replace('Hello', 'Hi')
결과: 'Hi World Hi'

왼쪽부터
첫 번째 등장

오른쪽부터
마지막 등장

전체 등장 횟수

교체가 적용된
새 문자열

이러한 검색과 교체 메서드는 텍스트 처리, 데이터 정리, 문자열 조작에서 기본적인 도구가 됩니다.

5.6) 문자열과 숫자 간 변환

프로그래밍에서 가장 흔한 작업 중 하나는 텍스트와 숫자 표현 사이를 변환하는 일입니다. input() 으로 사용자 입력을 읽으면, 사용자가 숫자를 입력하더라도 항상 문자열을 얻게 됩니다. 반대로 숫자를 텍스트로 보여 주고 싶을 때는 숫자를 문자열로 변환해야 합니다.

5.6.1) 문자열을 숫자로 변환하기

3장에서도 int()float() 함수를 살펴봤지만, 여기서는 조금 더 자세히 알아보겠습니다:

python
# string_to_number.py
# 문자열을 정수로 변환
age_text = "25"
age = int(age_text)
print(age)        # Output: 25
print(type(age))  # Output: <class 'int'>
 
# 문자열을 실수로 변환
price_text = "19.99"
price = float(price_text)
print(price)        # Output: 19.99
print(type(price))  # Output: <class 'float'>

이러한 변환은 사용자 입력을 처리할 때 필수적입니다:

python
# user_input_conversion.py
# 사용자 입력을 흉내 냄 (실제 코드에서는 input() 사용)
user_age = "30"
user_height = "5.9"
 
# 숫자로 변환해서 수학 연산 가능하게 만들기
age = int(user_age)
height = float(user_height)
 
# 이제 계산을 수행할 수 있음
print(f"In 10 years, you'll be {age + 10}")  # Output: In 10 years, you'll be 40
print(f"Your height in meters: {height * 0.3048:.2f}")  # Output: Your height in meters: 1.80

중요: 문자열은 유효한 숫자를 나타내야만 변환이 가능합니다. 그렇지 않으면 에러가 발생합니다:

python
# conversion_errors.py
# 이것들은 문제없음
print(int("123"))      # Output: 123
print(float("3.14"))   # Output: 3.14
 
# 이것들은 ValueError 를 발생시킴:
# print(int("hello"))     # ValueError: invalid literal for int()
# print(int("12.5"))      # ValueError: invalid literal for int() with base 10
# print(float("12.5.3"))  # ValueError: could not convert string to float

이러한 에러를 우아하게 처리하는 방법은 28장에서 배웁니다. 지금은, 문자열이 유효한 숫자를 나타내지 않으면 변환이 실패한다는 점만 알고 있으면 됩니다.

5.6.2) 숫자 문자열의 공백 처리

Python의 변환 함수는 앞뒤에 있는 공백을 자동으로 처리해 줍니다:

python
# whitespace_handling.py
# 공백이 있어도 모두 잘 동작함
print(int("  42  "))      # Output: 42
print(float("  3.14  "))  # Output: 3.14
 
# 안전을 위해 strip() 과 변환을 결합
user_input = "  100  "
number = int(user_input.strip())
print(number)  # Output: 100

사용자 입력은 종종 여분의 공백을 포함하기 때문에, 이는 매우 유용합니다.

5.6.3) 숫자를 문자열로 변환하기

str() 함수는 어떤 값이든 그 값의 문자열 표현으로 변환합니다:

python
# number_to_string.py
age = 25
height = 5.9
 
# 숫자를 문자열로 변환
age_text = str(age)
height_text = str(height)
 
print(type(age_text))     # Output: <class 'str'>
print(type(height_text))  # Output: <class 'str'>
 
# 이제 다른 문자열과 이어 붙일 수 있음
message = "I am " + str(age) + " years old"
print(message)  # Output: I am 25 years old

숫자를 문자열과 결합하려 할 때 항상 필요합니다:

python
# concatenation_with_numbers.py
score = 95
total = 100
 
# 이어 붙이기를 위해서는 숫자를 문자열로 변환해야 함
result = "Score: " + str(score) + "/" + str(total)
print(result)  # Output: Score: 95/100
 
# 대안: f-string 사용 (6장에서 자세히 다룹니다)
result = f"Score: {score}/{total}"
print(result)  # Output: Score: 95/100

5.6.4) 정수와 실수 간 변환

정수 타입과 실수 타입 사이의 변환도 가능합니다:

python
# int_float_conversion.py
# 실수에서 정수로 (소수 부분을 잘라냄)
price = 19.99
price_int = int(price)
print(price_int)  # Output: 19 (소수 부분이 잘리고, 반올림되지 않음)
 
# 정수에서 실수로
age = 25
age_float = float(age)
print(age_float)  # Output: 25.0

중요: 실수를 정수로 변환하면 소수 부분이 잘려 나가며, 반올림하지 않습니다:

python
# truncation_not_rounding.py
print(int(3.9))   # Output: 3 (4가 아님!)
print(int(3.1))   # Output: 3
print(int(-3.9))  # Output: -3 (0을 향해 잘라냄)
 
# 반올림하려면 먼저 round() 를 사용합니다 (4장에서 다룹니다)
print(int(round(3.9)))  # Output: 4

5.6.5) 실용적인 변환 예제

형 변환이 필수적인 실제 상황은 다음과 같습니다:

python
# practical_conversions.py
# 사용자 입력 읽고 처리하기
# (input() 을 흉내 냄 - 실제 코드에서는 input() 사용)
user_input = "42"
 
# 숫자로 변환해서 계산 수행
number = int(user_input)
doubled = number * 2
print(f"Double of {number} is {doubled}")  # Output: Double of 42 is 84
 
# 형식 있는 출력 만들기
name = "John"
age = 30
height = 5.9
 
# 방법 1: 숫자를 문자열로 변환
info = name + " is " + str(age) + " years old and " + str(height) + " feet tall"
print(info)  # Output: John is 30 years old and 5.9 feet tall
 
# 방법 2: f-string 사용 (더 읽기 쉬움 - 6장에서 다룸)
info = f"{name} is {age} years old and {height} feet tall"
print(info)  # Output: John is 30 years old and 5.9 feet tall
 
# 파일에서 읽은 데이터 처리 (미리보기)
data_line = "100,200,300"  # CSV 파일에서 읽은 한 줄을 흉내 냄
numbers = data_line.split(",")  # 문자열 리스트로 분리
total = int(numbers[0]) + int(numbers[1]) + int(numbers[2])
print(f"Total: {total}")  # Output: Total: 600

5.6.6) 흔한 변환 함정

다음과 같은 흔한 실수들을 주의하세요:

python
# conversion_pitfalls.py
# 함정 1: 숫자가 아닌 문자열을 변환하려고 시도
# text = "hello"
# number = int(text)  # ValueError!
 
# 함정 2: 변환하지 않고 바로 산술 연산을 하려는 경우
age_text = "25"
# next_year = age_text + 1  # TypeError: can only concatenate str to str
 
# 올바른 방법:
age = int(age_text)
next_year = age + 1
print(next_year)  # Output: 26
 
# 함정 3: int() 사용으로 정밀도 손실
price = 19.99
price_int = int(price)  # 20이 아니라 19가 됨!
print(price_int)  # Output: 19
 
# 함정 4: 콤마나 통화 기호가 있는 문자열을 그대로 변환하려는 경우
# price_text = "$1,234.56"
# price = float(price_text)  # ValueError!
 
# 먼저 문자열을 정리해야 합니다:
price_text = "$1,234.56"
clean_price = price_text.replace("$", "").replace(",", "")
price = float(clean_price)
print(price)  # Output: 1234.56

형 변환을 이해하는 것은 사용자와 상호작용하고, 실제 데이터를 처리하는 프로그램을 만드는 데 매우 중요합니다. Python 프로그래밍 여정 내내 이런 변환을 계속 사용하게 될 것입니다.

5.7) in 과 not in 으로 부분 문자열 검사하기

Python에서는 innot in 연산자를 사용해 한 문자열 안에 다른 문자열이 포함되어 있는지 간단하고 읽기 쉽게 검사할 수 있습니다. 이는 검증(validation), 필터링, 의사 결정 로직을 구현할 때 매우 유용합니다.

5.7.1) in 으로 부분 문자열 확인하기

in 연산자는 한 문자열 안에 다른 문자열이 있으면 True, 그렇지 않으면 False 를 반환합니다:

python
# in_operator.py
text = "Python is a powerful programming language"
 
# 부분 문자열이 존재하는지 확인
print("Python" in text)      # Output: True
print("powerful" in text)    # Output: True
print("Java" in text)        # Output: False

이는 find()index() 를 사용하는 것보다 훨씬 읽기 좋습니다:

python
# in_vs_find.py
text = "Hello, World!"
 
# in 사용 (명확하고 읽기 좋음)
if "World" in text:
    print("Found World!")  # Output: Found World!
 
# find 사용 (덜 읽기 좋음)
if text.find("World") != -1:
    print("Found World!")  # Output: Found World!

in 연산자는 대소문자를 구분합니다:

python
# case_sensitivity.py
text = "Python Programming"
 
print("python" in text)   # Output: False (소문자 'p')
print("Python" in text)   # Output: True (대문자 'P')
 
# 대소문자를 무시하고 검사하려면 먼저 소문자로 변환
print("python" in text.lower())  # Output: True

5.7.2) not in 으로 부재 여부 확인하기

not in 연산자는 부분 문자열이 포함되어 있지 않은지 를 검사합니다:

python
# not_in_operator.py
text = "Python is great"
 
print("Java" not in text)     # Output: True (Java 는 없음)
print("Python" not in text)   # Output: False (Python 은 있음)

검증(validation)에 특히 유용합니다:

python
# validation_examples.py
# 사용자 이름에 허용되지 않는 공백이 있는지 검사
username = "john_smith"
 
if " " not in username:
    print("Username is valid (no spaces)")  # Output: Username is valid (no spaces)

5.7.3) 추가적인 문자열 검사 메서드

Python은 문자열의 속성을 검사하기 위한 여러 유용한 메서드를 제공합니다:

python
# string_checking_methods.py
text = "Python"
 
# 특정 문자열로 시작하는지 확인
print(text.startswith("Py"))   # Output: True
print(text.startswith("Ja"))   # Output: False
 
# 특정 문자열로 끝나는지 확인
print(text.endswith("on"))     # Output: True
print(text.endswith("ing"))    # Output: False
 
# in 을 사용하는 것보다 더 정확한 경우가 많음
filename = "report.txt"
print(filename.endswith(".txt"))  # Output: True
print(".txt" in filename)         # Output: True (하지만 덜 정확한 방법)
 
# startswith/endswith 는 여러 옵션을 한 번에 검사할 수 있음
filename = "document.pdf"
print(filename.endswith((".pdf", ".doc", ".txt")))  # Output: True

이러한 검사 메서드는 입력 검증, 데이터 필터링, 조건 로직에 필수적인 도구입니다. 수동으로 문자열을 검색하는 것보다 코드가 훨씬 읽기 쉽고 유지보수도 용이합니다.

5.8) 문자열은 불변이다: 실제로 무엇을 의미하는가

Python 문자열의 가장 중요한 특징 중 하나는 문자열이 불변(immutable) 이라는 것입니다. 한 번 만들어진 문자열은 변경할 수 없습니다. 처음에는 제약처럼 느껴질 수 있지만, 불변성을 이해하는 것은 올바른 Python 코드를 작성하고 미묘한 버그를 피하는 데 매우 중요합니다.

5.8.1) 불변성의 의미

문자열이 불변이라는 것은, 이미 존재하는 문자열의 문자를 직접 수정할 수 없다는 뜻입니다. 문자열을 "변경"하는 것처럼 보이는 모든 연산은 사실 새로운 문자열을 만듭니다:

python
# immutability_basics.py
text = "Hello"
 
# 이 코드는 문자열을 바꾸는 것처럼 보이지만 실제로는 그렇지 않습니다
text = text + " World"
print(text)  # Output: Hello World
 
# 실제로는 다음과 같은 일이 일어납니다:
# 1. Python은 새로운 문자열 "Hello World" 를 생성합니다
# 2. 변수 'text' 는 이제 이 새로운 문자열을 가리킵니다
# 3. 원래의 "Hello" 문자열은 (가비지 컬렉션되기 전까지) 그대로 존재합니다

개별 문자를 직접 바꿀 수는 없습니다:

python
# cannot_modify_characters.py
text = "Hello"
 
# 이것은 에러를 발생시킵니다:
# text[0] = "J"  # TypeError: 'str' object does not support item assignment
 
# 대신 새로운 문자열을 만들어야 합니다
text = "J" + text[1:]
print(text)  # Output: Jello

이는 리스트가 동작하는 방식과 근본적으로 다릅니다(리스트에 대해서는 13장에서 배웁니다). 리스트(list)는 가변(mutable) 하므로, 원소를 바꿀 수 있습니다:

python
# lists_are_mutable.py
# 리스트 미리보기 (13장에서 자세히 다룸)
numbers = [1, 2, 3]
numbers[0] = 10  # 리스트에서는 문제가 없음
print(numbers)   # Output: [10, 2, 3]
 
# 하지만 문자열은 허용하지 않습니다:
text = "Hello"
# text[0] = "J"  # 문자열에서는 TypeError!

5.8.2) 문자열 메서드가 항상 새 문자열을 반환하는 이유

문자열을 "수정"하는 것처럼 보이는 모든 문자열 메서드는 실제로는 새로운 문자열을 반환하며, 원래 문자열은 그대로 둡니다:

python
# methods_return_new_strings.py
original = "hello world"
 
# 이 메서드들은 모두 새 문자열을 반환합니다
uppercase = original.upper()
capitalized = original.capitalize()
replaced = original.replace("world", "Python")
 
# 원래 문자열은 변경되지 않음
print(original)      # Output: hello world
print(uppercase)     # Output: HELLO WORLD
print(capitalized)   # Output: Hello world
print(replaced)      # Output: hello Python

그래서 변경 내용을 유지하려면 결과를 변수에 할당(또는 같은 변수에 다시 저장)해야 합니다:

python
# keeping_changes.py
text = "  hello  "
 
# 잘못된 예: 결과를 사용하지 않음
text.strip()
print(text)  # Output:   hello   (공백이 그대로 남아 있음!)
 
# 올바른 예: 결과를 할당
text = text.strip()
print(text)  # Output: hello (공백이 제거됨)

이는 초보자가 자주 저지르는 실수입니다:

python
# common_mistake.py
message = "python programming"
 
# 실수: 메서드를 호출하지만 결과를 사용하지 않음
message.upper()
message.replace("python", "Python")
print(message)  # Output: python programming (변경되지 않음!)
 
# 올바른 방법: 결과를 할당
message = message.upper()
message = message.replace("PYTHON", "Python")
print(message)  # Output: Python PROGRAMMING

5.8.3) 불변성이 갖는 의미

불변성을 이해하면 더 나은 코드를 작성할 수 있습니다:

1. 문자열은 공유해도 안전하다:

python
# safe_sharing.py
original = "Hello"
copy = original  # 두 변수 모두 같은 문자열을 가리킴
 
# 문자열은 불변이기 때문에, 이렇게 공유해도 안전합니다
copy = copy + " World"
 
print(original)  # Output: Hello (변경되지 않음)
print(copy)      # Output: Hello World (새 문자열)

2. 문자열 연산은 새 객체를 만든다:

python
# new_objects.py
text = "Python"
 
# 각 연산은 새로운 문자열 객체를 생성
result1 = text.upper()
result2 = text.lower()
result3 = text.replace("P", "J")
 
# 모두 다른 객체
print(id(text))     # 어떤 메모리 주소
print(id(result1))  # 다른 메모리 주소
print(id(result2))  # 또 다른 메모리 주소
print(id(result3))  # 또 다른 메모리 주소

3. 반복문에서 문자열을 쌓아 올리면 비효율적일 수 있다:

python
# inefficient_string_building.py
# 이 코드는 많은 임시 문자열 객체를 생성합니다
result = ""
for i in range(5):
    result = result + str(i)  # 매번 새로운 문자열 생성
print(result)  # Output: 01234
 
# 더 효율적인 방법 (많은 이어 붙이기가 필요할 때):
# 리스트와 join 사용 (6장에서 배웁니다)
parts = []
for i in range(5):
    parts.append(str(i))
result = "".join(parts)
print(result)  # Output: 01234

5.8.4) 불변성과 함수 인자

문자열을 함수에 전달할 때, 함수 안에서 문자열이 실수로 변경될까 걱정할 필요가 없습니다:

python
# safe_function_arguments.py
def process_text(text):
    # 어떤 연산이든 새 문자열을 생성합니다
    text = text.upper()
    text = text.replace("A", "X")
    return text
 
original = "banana"
result = process_text(original)
 
print(original)  # Output: banana (변경되지 않음)
print(result)    # Output: BXNXNX (변경된 버전)

이는 mutable 타입(예: 리스트, 13장에서 배웁니다)과 다릅니다. mutable 타입은 함수 안에서 수정하면 원본 객체에 영향을 줍니다.

5.8.5) 불변성 시각화

문자열을 "수정"할 때 실제로 어떤 일이 일어나는지 시각적으로 표현해 보겠습니다:

text = 'Hello'

메모리: 'Hello' (주소 1000)

text = text + ' World'

무슨 일이
일어날까?

1. 새 문자열 'Hello World' 생성
주소 2000
2. 변수 'text' 는 이제 주소 2000을 가리킴
3. 원래의 'Hello' (주소 1000)는
가비지 컬렉션 전까지 남아 있음

text 는 이제 'Hello World' 를 가리킴

문자열이 불변이라는 사실을 이해하면 다음과 같은 점에서 도움이 됩니다:

  1. 메서드 결과를 저장하는 것을 잊는 실수를 피할 수 있습니다.
  2. 문자열 연산이 새로운 객체를 생성하는 이유를 이해하게 됩니다.
  3. 큰 문자열을 만들 때 더 효율적인 코드를 작성할 수 있습니다.
  4. 프로그램의 여러 부분에서 문자열을 안심하고 공유할 수 있습니다.

이러한 불변성은 문자열을 리스트 같은 가변 타입과 구분 짓는 기본적인 특징입니다. 리스트와 같은 가변 타입은 이 책의 IV부에서 자세히 살펴봅니다.


챕터 요약:

이 장에서는 Python에서 문자열을 사용해 텍스트를 다루는 기초를 배웠습니다. 이제 여러분은 다음을 이해하고 있습니다:

  • 따옴표와 이스케이프 시퀀스를 사용해 문자열 리터럴을 만드는 방법
  • 이어 붙이기와 반복으로 문자열을 결합하는 방법
  • 인덱싱과 슬라이싱으로 개별 문자와 부분 문자열을 다루는 방법
  • 대소문자 변환과 공백 제거 메서드로 문자열을 변형하는 방법
  • 문자열 안에서 텍스트를 검색하고 교체하는 방법
  • 입력 처리와 출력 서식을 위해 문자열과 숫자 사이를 변환하는 방법
  • innot in 연산자를 사용해 부분 문자열을 검사하는 방법
  • 문자열이 불변이라는 사실과, 이것이 코드에 어떤 의미를 가지는지

이러한 문자열 조작 기술은 Python에서 텍스트 처리를 위한 기반을 이룹니다. 사용자 인터페이스를 만들고, 데이터 파일을 처리하고, 입력을 검증하고, 출력을 서식화할 때 이 기법들을 끊임없이 사용하게 될 것입니다.

다음 장에서는 이 기초 위에 더 나아가, 문자열 분할(splitting)과 결합(joining), f-string 과 format() 메서드를 이용한 강력한 서식 지정, 그리고 국제 문자 처리를 위한 텍스트 인코딩까지, 더 고급 문자열 처리 기법들을 살펴보겠습니다.

© 2025. Primesoft Co., Ltd.
support@primesoft.ai