문자열도 인덱스로 다룬다
리스트에서 쓰던 규칙이 그대로 통합니다.
input이 반환하는 값도, 파일에서 읽어 오는 내용도 문자열입니다.
그래서 프로그램이 하는 일의 상당 부분은 입력된 문자열을 쓸 수 있는 형태로 정리하는 것입니다.
다행히 새로 외울 것이 많지 않습니다 —
문자열은 글자가 순서대로 이어진 값이라, 리스트에서 쓰던 방법이 거의 그대로 통합니다.
여기서부터는 따옴표로 묶은 값 전체를 문자열, 그 안의 하나하나를 글자라고 구별해 부릅니다.
word = "python"
print(word[0]) # p 인덱스는 0부터 센다
print(word[3]) # h
print(word[-1]) # n 뒤에서 첫 번째
print(len(word)) # 6 글자 수인덱스는 0부터
"python"의 p가 인덱스 0이고 마지막 n이 인덱스 5입니다.
인덱스를 0부터 세는 것도, 음수 인덱스가 뒤에서부터 세는 것도, len이 글자 수를 반환하는 것도
리스트에서 본 그대로입니다.
슬라이싱도 같습니다. 날짜처럼 글자마다 위치가 정해진 문자열에서 특히 쓸모가 있습니다.
day = "2026-08-12"
print(day[0:4]) # 2026 인덱스 0부터 4 「앞」까지
print(day[5:7]) # 08
print(day[:4]) # 2026 처음부터
print(day[5:]) # 08-12 끝까지끝 인덱스가 빠지는 것도 같습니다
day[0:4]에 인덱스 4는 들어가지 않습니다.
그래서 두 인덱스를 빼기만 하면 길이가 나옵니다 — 4 − 0으로 네 글자입니다.
for로 한 글자씩 꺼내 반복할 수도 있고, in으로 어떤 문자열이 들어 있는지 확인할 수도 있습니다.
word = "python"
for ch in word: # 리스트에서 값을 꺼내던 것과 같은 방식이다
print(ch, end=" ") # p y t h o n
print()
print("th" in word) # True 들어 있는지 확인한다
print("z" in word) # False스스로 확인
시각을 적은 「13:45:20」에서 분에 해당하는 두 글자만 꺼내려면 어디부터 어디까지 잘라야 할까요?
만든 문자열은 바꿀 수 없다
리스트와 닮았지만 여기서 달라집니다.
리스트는 scores[1] = 88처럼 인덱스를 지정해 요소 하나만 바꿀 수 있었습니다.
문자열에 같은 것을 해 보면 어떻게 될까요?
word = "python"
word[0] = "P" # TypeError: 'str' object does not support item assignment리스트 — 바꿀 수 있다
인덱스를 지정해 요소의 값을 바꿀 수 있습니다. 원래 리스트 자체가 바뀝니다.
문자열 — 바꿀 수 없다
인덱스를 지정해 한 글자만 바꾸려 하면 오류가 납니다. 바꾸려면 새 문자열을 만들어야 합니다.
word = "python"
word = "P" + word[1:] # 앞 한 글자만 바꾼 「새」 문자열을 만들어 다시 대입한다
print(word) # Python그래서 「다시 대입」이 늘 따라옵니다
문자열을 다루는 코드에 word = ...word... 형태가 자주 나오는 이유가 이것입니다.
원래 문자열을 고친 것이 아니라, 새로 만든 문자열을 같은 변수에 다시 대입한 것입니다.
이 습관은 「문자열 메서드」 절에서 그대로 쓰입니다.
스스로 확인
문자열을 바꿀 수 없다면, 「이름의 첫 글자만 대문자로 만들기」는 어떤 순서로 해야 할까요?
문자열 메서드
값 뒤에 점을 찍고 부르면 그 값을 다룬 결과가 나옵니다.
사용자가 입력한 문자열에는 앞뒤에 공백이 붙거나 대소문자가 뒤섞이기 쉽습니다.
그대로 비교하면 " Seoul "과 "seoul"이 서로 다른 값으로 판단됩니다.
이런 정리를 위해 문자열에는 값에 딸린 기능들이 있습니다.
메서드(method)
값에 딸린 함수를 메서드라고 합니다. 값 뒤에 점을 찍고 부릅니다.
len(word)처럼 값을 괄호 안에 넣는 함수와 달리
word.upper()는 「이 값의」 기능이라는 뜻이 됩니다.
scores.append(90)도 리스트에 딸린 메서드입니다.
점 앞이 값이 아니라 math처럼 관련 있는 함수들을 모아 둔 묶음(모듈)의 이름이면, 그것은 메서드가 아니라 그 묶음 안의 함수입니다.
answer = " Seoul "
print(answer.strip()) # Seoul 앞뒤 공백을 떼어 낸다
print(answer.strip().upper()) # SEOUL 모두 대문자로
print(answer.strip().lower()) # seoul 모두 소문자로반환값을 저장하지 않으면 결과가 남지 않습니다
문자열은 바꿀 수 없으므로, 이 메서드들은 원본을 그대로 두고 정리한 새 문자열을 반환합니다. 반환값을 변수에 저장하지 않으면 그대로 사라집니다.
answer = " Seoul "
answer.strip() # 반환값을 어디에도 저장하지 않았다
print(answer) # 「 Seoul 」 원본은 그대로다
answer = answer.strip() # 다시 대입해야 정리된 값이 남는다
print(answer) # Seoul문자열을 찾거나 바꾸는 메서드도 자주 씁니다.
sentence = "나는 사과를 좋아한다. 사과는 맛있다."
print(sentence.count("사과")) # 2 몇 번 나오는지
print(sentence.find("사과")) # 3 처음 나오는 인덱스
print(sentence.find("포도")) # -1 없으면 -1
print(sentence.replace("사과", "포도")) # 나는 포도를 좋아한다. 포도는 맛있다.| 쓰는 법 | 하는 일 | 반환값 |
|---|---|---|
.strip() |
앞뒤의 공백 · 줄바꿈 같은 공백 문자를 떼어 낸다 (가운데는 그대로 둔다) | 새 문자열 |
.upper() .lower() |
모두 대문자로 / 모두 소문자로 (대소문자가 있는 글자에만 해당하고, 한글은 그대로다) | 새 문자열 |
.replace(a, b) |
a를 b로 바꾼다. 나오는 것을 전부 바꾼다 |
새 문자열 |
.count(a) |
a가 몇 번 나오는지 센다 |
정수 |
.find(a) |
a가 처음 나오는 인덱스. 없으면 −1 |
정수 |
조건에 맞는지 검사만 하는 메서드도 있습니다. True나 False를 반환하므로 if의 조건식에 바로 쓸 수 있습니다.
code = "A-2026"
num = "2026"
print(code.startswith("A")) # True 이렇게 시작하는지
print(code.endswith("6")) # True 이렇게 끝나는지
print(num.isdigit()) # True 숫자로만 되어 있는지
print(code.isdigit()) # False변환하기 전에 isdigit으로 확인합니다
int(input())은 사용자가 정수로 변환할 수 없는 값을 입력하면 오류가 나며 멈춥니다.
변환하기 전에 검사하면 멈추는 대신 다시 입력받을 수 있습니다.
다만 isdigit은 0부터 9까지의 숫자로만 되어 있는지 검사하므로,
「-5」 같은 음수나 「3.5」처럼 숫자로 변환할 수 있는 문자열에도 False를 반환합니다.
스스로 확인
" Seoul ".strip().upper()처럼 메서드를 점으로 이어 쓸 수 있는 것은, 앞 메서드가 무엇을 반환하기 때문일까요?
나누고 잇기
문자열과 리스트를 서로 변환하는 한 쌍입니다.
한 줄로 입력된 문자열을 여러 값으로 나누어 처리하고, 처리가 끝나면
다시 한 줄로 이어 출력하는 일이 자주 있습니다. split과 join이 이 두 일을 맡습니다.
split — 문자열 → 리스트
기준 문자열을 경계로 나누고, 나뉜 값을 순서대로 리스트에 넣어 반환합니다.
join — 리스트 → 문자열
사이에 넣을 문자열을 점 앞에 두고, 리스트의 요소를 하나의 문자열로 잇습니다.
line = "사과,바나나,포도"
print(line.split(",")) # ['사과', '바나나', '포도'] 쉼표를 기준으로 나눈다
print(line.split(",")[0]) # 사과 결과가 「리스트」이므로 인덱스로 꺼낼 수 있다
print(" 한 줄 로 ".split()) # ['한', '줄', '로'] 기준을 지정하지 않으면 공백을 기준으로 나눈다
input().split()처럼 한 줄로 입력된 여러 값을 나눌 때 쓰던 메서드입니다. 결과가
리스트이므로, 인덱스로 꺼내거나 반복문으로 순회할 수 있습니다.
fruits = ["사과", "바나나", "포도"]
print(", ".join(fruits)) # 사과, 바나나, 포도 사이에 넣을 문자열을 앞에 적는다
print("-".join(fruits)) # 사과-바나나-포도
print("".join(fruits)) # 사과바나나포도
scores = [90, 85, 72]
# print(", ".join(scores)) # 오류. 요소가 모두 문자열이어야 한다
texts = []
for s in scores:
texts.append(str(s)) # 하나씩 문자열로 변환해 추가하고
print(", ".join(texts)) # 90, 85, 72이을 요소는 모두 문자열이어야 합니다
join은 문자열을 잇는 메서드라서 숫자가 섞여 있으면 오류가 납니다.
str로 변환해 넣습니다 —
문자열과 숫자를 +로 이을 수 없었던 것과 같은 이유입니다.
사이에 넣을 문자열을 앞에 적는 이유
", ".join(fruits)는 「쉼표와 공백으로 fruits의 요소를 이어라」로 읽습니다.
잇는 방식이 사이에 넣는 문자열에 달려 있어서, join을 그 문자열의 메서드로 만든 것입니다.
스스로 확인
「사과,바나나,포도」를 「사과 / 바나나 / 포도」로 바꾸려면 어떤 메서드를 어떤 순서로 쓸까요?
서식을 지정해 출력하기
값을 문장 안에 바로 넣습니다.
+로 이어 붙여 출력하면 값이 하나둘 늘어날수록
따옴표와 str이 뒤엉켜 읽기 어려워집니다.
name = "학생 A"
avg = 78.456
print("이름: " + name + ", 평균: " + str(avg)) # 지금까지 하던 방법
print(f"이름: {name}, 평균: {avg}") # 따옴표 앞에 f를 붙이고 「{}」 안에 값을 적는다f 문자열(f-string)
여는 따옴표 앞에 f를 붙이면, 그 안의
{ }가 값이 들어갈 위치가 됩니다.
str로 변환할 필요도 없습니다 — 값이 자동으로 문자열로 변환되어 들어갑니다.
출력될 문장의 모양이 코드에 그대로 보인다는 것이 장점입니다.
{ } 안의 값 뒤에 콜론을 찍고 서식을 덧붙이면 출력 형식을 지정할 수 있습니다.
평균처럼 소수점 아래가 길게 늘어지는 값에 특히 쓸모가 있습니다.
avg = 78.456
total = 1234567
print(f"{avg:.1f}") # 78.5 소수점 아래 「한」 자리까지 (반올림한다)
print(f"{avg:.2f}") # 78.46
print(f"{total:,}") # 1,234,567 천 단위마다 쉼표| 서식 | 출력 예 | 뜻 |
|---|---|---|
:.1f |
78.5 | 소수점 아래 한 자리까지. 그 아래는 반올림한다(딱 절반인 값은 round처럼 짝수 쪽으로 갈 수 있다) |
:.2f |
78.46 | 소수점 아래 두 자리까지 |
:, |
1,234,567 | 천 단위마다 쉼표를 넣는다 |
f를 빠뜨리면 조용히 틀립니다
오류가 나지 않고 {name}이 중괄호째 그대로 출력됩니다.
중괄호가 그대로 보이면 f부터 확인합니다.
name = "학생 A"
print("안녕, {name}!") # 안녕, {name}! f가 없으면 평범한 문자열이다
print(f"안녕, {name}!") # 안녕, 학생 A!배운 것을 모두 이어 봅니다
한 줄에 적힌 도시 이름들을 나누고 → 정리해 → 리스트에 추가하고 → 다시 이어 출력합니다. 문자열을 다루는 코드는 흔히 이런 흐름입니다.
raw = " seoul , busan , daegu "
cities = []
for piece in raw.split(","):
cities.append(piece.strip().upper())
print(cities) # ['SEOUL', 'BUSAN', 'DAEGU']
print(", ".join(cities)) # SEOUL, BUSAN, DAEGU
print(f"도시 {len(cities)}곳을 정리했습니다.") # 도시 3곳을 정리했습니다.스스로 확인
공백을 떼는 strip을 빼면 어떤 값이 리스트에 저장될까요? 그 값으로 비교를 하면 무엇이 어긋날까요?
핵심 정리
규칙은 리스트와 같다
인덱스는 0부터 세고, 음수는 뒤에서 세고, 잘라 낼 때 끝은 빠진다.
len·in·for도 그대로 쓴다.
바꿀 수 없다
인덱스로 한 글자만 바꾸려 하면 오류다. 바꾸려면 새 문자열을 만들어 다시 대입한다. 리스트와 다른 점이다.
문자열 메서드는 원본을 바꾸지 않는다
strip·upper·replace는 원본을 그대로 두고
정리한 새 문자열을 반환한다. 반환값을 저장하지 않으면 사라진다.
split과 join
나누면 리스트가 되고, 이으면 문자열이 된다.
join으로 이을 요소는 모두 문자열이어야 한다.
f 문자열
따옴표 앞에 f를 붙이면 { } 안의 값이 문자열에 들어간다.
콜론 뒤에 .1f·,를 덧붙여 출력 형식을 지정한다.
중괄호가 그대로 출력되면 f를 빠뜨린 것이다.
확인 퀴즈
배운 내용을 확인해 봅시다.
1. word = "python"일 때 word[1:4]는?
2. answer = " seoul " 다음에 answer.strip()만 적고 answer를 출력하면?
3. 다음 중 틀린 설명은?