본문으로 건너뛰기

문자열 처리

문자열 생성

다양한 방법

# 작은따옴표
name = 'Python'

# 큰따옴표
message = "Hello, World!"

# 삼중 따옴표 (여러 줄)
text = """첫 번째 줄
두 번째 줄
세 번째 줄"""

poem = '''장미는 빨갛고
제비꽃은 파랗다'''

# 이스케이프 시퀀스
quote = "He said, \"Hello!\""
path = "C:\\Users\\Documents"
new_line = "첫 줄\n두 번째 줄"
tab = "이름\t나이"

# raw 문자열 (이스케이프 무시)
path = r"C:\Users\Documents"

문자열 인덱싱과 슬라이싱

인덱싱

text = "Python"

# 양수 인덱스 (왼쪽부터 0, 1, 2...)
print(text[0]) # P
print(text[1]) # y
print(text[5]) # n

# 음수 인덱스 (오른쪽부터 -1, -2, -3...)
print(text[-1]) # n
print(text[-2]) # o
print(text[-6]) # P

# 에러
# print(text[10]) # IndexError

슬라이싱

text = "Python Programming"

# [시작:끝] - 끝은 포함 안 됨
print(text[0:6]) # Python
print(text[7:18]) # Programming

# 생략 가능
print(text[:6]) # Python (처음부터)
print(text[7:]) # Programming (끝까지)
print(text[:]) # Python Programming (전체)

# 음수 인덱스
print(text[-11:]) # Programming
print(text[:-12]) # Python

# 스텝 지정 [시작:끝:스텝]
print(text[::2]) # Pto rgamn (2칸씩)
print(text[::-1]) # gnimmargorP nohtyP (역순)

# 실용 예제
url = "https://www.example.com"
domain = url[8:-4] # www.example
print(domain)

문자열 연산

연결과 반복

# 연결 (+)
first = "Hello"
second = "World"
greeting = first + " " + second
print(greeting) # Hello World

# 반복 (*)
line = "=" * 20
print(line) # ====================

border = "-" * 10
print(f"{border} 제목 {border}")
# ---------- 제목 ----------

# 여러 문자열 연결
words = ["Python", "is", "awesome"]
sentence = " ".join(words)
print(sentence) # Python is awesome

비교

# 같음/다름
print("hello" == "hello") # True
print("hello" != "Hello") # True

# 대소 비교 (사전순)
print("apple" < "banana") # True
print("apple" < "Apple") # False (대문자가 먼저)

# 포함 여부
text = "Python Programming"
print("Python" in text) # True
print("Java" in text) # False
print("Java" not in text) # True

문자열 메서드

대소문자 변환

text = "Hello, Python!"

print(text.upper()) # HELLO, PYTHON!
print(text.lower()) # hello, python!
print(text.capitalize()) # Hello, python!
print(text.title()) # Hello, Python!
print(text.swapcase()) # hELLO, pYTHON!

# 실용 예제 - 사용자 입력 정규화
user_input = " YES "
if user_input.strip().lower() == "yes":
print("확인되었습니다")

검색과 확인

text = "Python Programming"

# 찾기
print(text.find("Python")) # 0 (첫 위치)
print(text.find("Java")) # -1 (없음)
print(text.index("Programming")) # 7
# print(text.index("Java")) # ValueError

# 개수 세기
print(text.count("o")) # 1
print(text.count("m")) # 3

# 시작/끝 확인
print(text.startswith("Python")) # True
print(text.endswith("ing")) # True

# 포함 확인
print("gram" in text) # True

문자 타입 확인

# 알파벳만
print("abc".isalpha()) # True
print("abc123".isalpha()) # False

# 숫자만
print("123".isdigit()) # True
print("12.3".isdigit()) # False

# 알파벳 + 숫자
print("abc123".isalnum()) # True
print("abc 123".isalnum()) # False

# 공백만
print(" ".isspace()) # True
print(" a ".isspace()) # False

# 대문자/소문자
print("ABC".isupper()) # True
print("abc".islower()) # True

# 실용 예제 - 비밀번호 검증
password = "Pass123"
has_digit = any(c.isdigit() for c in password)
has_upper = any(c.isupper() for c in password)
has_lower = any(c.islower() for c in password)

if len(password) >= 8 and has_digit and has_upper and has_lower:
print("강한 비밀번호입니다")

공백 제거

text = "   hello world   "

print(text.strip()) # "hello world" (양쪽)
print(text.lstrip()) # "hello world " (왼쪽)
print(text.rstrip()) # " hello world" (오른쪽)

# 특정 문자 제거
url = "https://example.com/"
print(url.strip("https://")) # example.com/
print(url.rstrip("/")) # https://example.com

# 실용 예제 - CSV 파싱
data = " 홍길동, 25, 서울 "
parts = [part.strip() for part in data.split(",")]
print(parts) # ['홍길동', '25', '서울']

변환과 치환

text = "Hello, Python!"

# 치환
print(text.replace("Python", "World")) # Hello, World!
print(text.replace("l", "L")) # HeLLo, Python!
print(text.replace("l", "L", 1)) # HeLlo, Python! (1개만)

# 분리
words = text.split(", ")
print(words) # ['Hello', 'Python!']

csv = "홍길동,25,서울"
data = csv.split(",")
print(data) # ['홍길동', '25', '서울']

# 연결
words = ["Python", "is", "fun"]
sentence = " ".join(words)
print(sentence) # Python is fun

# 특정 문자로 연결
print("-".join(words)) # Python-is-fun

# 줄 분리
text = """첫 줄
두 번째 줄
세 번째 줄"""
lines = text.splitlines()
print(lines) # ['첫 줄', '두 번째 줄', '세 번째 줄']

정렬

# 왼쪽 정렬
print("Python".ljust(10)) # "Python "
print("Python".ljust(10, "-")) # "Python----"

# 오른쪽 정렬
print("Python".rjust(10)) # " Python"
print("Python".rjust(10, "0")) # "0000Python"

# 중앙 정렬
print("Python".center(10)) # " Python "
print("Python".center(10, "*"))# "**Python**"

# 실용 예제 - 테이블 출력
print("이름".ljust(10) + "나이".rjust(5))
print("홍길동".ljust(10) + "25".rjust(5))
print("김철수".ljust(10) + "30".rjust(5))

문자열 포매팅

f-string (Python 3.6+, 추천)

name = "홍길동"
age = 25
height = 175.5

# 기본 사용
print(f"이름: {name}, 나이: {age}")

# 표현식
print(f"내년 나이: {age + 1}")
print(f"키(cm): {height}")

# 포맷 지정
price = 1234567
print(f"가격: {price:,}원") # 가격: 1,234,567원

pi = 3.14159265
print(f"원주율: {pi:.2f}") # 원주율: 3.14

# 정렬과 폭
print(f"{'Python':>10}") # " Python"
print(f"{'Python':<10}") # "Python "
print(f"{'Python':^10}") # " Python "
print(f"{'Python':*^10}") # "**Python**"

# 진수 표현
num = 255
print(f"10진수: {num}") # 10진수: 255
print(f"16진수: {num:x}") # 16진수: ff
print(f"8진수: {num:o}") # 8진수: 377
print(f"2진수: {num:b}") # 2진수: 11111111

format() 메서드

# 위치 기반
print("이름: {}, 나이: {}".format("홍길동", 25))

# 인덱스 지정
print("{1}, {0}".format("World", "Hello")) # Hello, World

# 이름 지정
print("이름: {name}, 나이: {age}".format(name="홍길동", age=25))

# 포맷 지정
print("가격: {:,}원".format(1234567))
print("비율: {:.1%}".format(0.856))

% 포매팅 (레거시)

name = "홍길동"
age = 25

print("이름: %s, 나이: %d" % (name, age))
print("비율: %.2f%%" % 85.678)

실전 예제

이메일 검증

def validate_email(email):
"""간단한 이메일 검증"""
# @ 포함 확인
if "@" not in email:
return False

# @를 기준으로 분리
parts = email.split("@")
if len(parts) != 2:
return False

local, domain = parts

# 로컬 파트와 도메인 검증
if not local or not domain:
return False

# 도메인에 . 포함 확인
if "." not in domain:
return False

return True

# 테스트
emails = [
"user@example.com", # ✅
"invalid.email", # ❌
"@example.com", # ❌
"user@", # ❌
]

for email in emails:
result = "유효" if validate_email(email) else "무효"
print(f"{email}: {result}")

텍스트 마스킹

def mask_phone(phone):
"""전화번호 마스킹"""
if len(phone) == 11:
return phone[:3] + "****" + phone[7:]
elif len(phone) == 10:
return phone[:3] + "***" + phone[6:]
return phone

def mask_email(email):
"""이메일 마스킹"""
local, domain = email.split("@")
if len(local) <= 2:
masked_local = local[0] + "*"
else:
masked_local = local[0] + "*" * (len(local) - 2) + local[-1]
return f"{masked_local}@{domain}"

# 사용
print(mask_phone("01012345678")) # 010****5678
print(mask_email("hong@example.com")) # h**g@example.com

문자열 분석기

def analyze_string(text):
"""문자열 상세 분석"""
return {
"길이": len(text),
"단어수": len(text.split()),
"대문자": sum(1 for c in text if c.isupper()),
"소문자": sum(1 for c in text if c.islower()),
"숫자": sum(1 for c in text if c.isdigit()),
"공백": sum(1 for c in text if c.isspace()),
"특수문자": sum(1 for c in text if not c.isalnum() and not c.isspace())
}

text = "Hello Python 2024! Welcome to coding."
result = analyze_string(text)

print("=== 문자열 분석 ===")
for key, value in result.items():
print(f"{key}: {value}")

URL 파서

def parse_url(url):
"""URL 파싱"""
# 프로토콜 분리
if "://" in url:
protocol, rest = url.split("://", 1)
else:
protocol = "http"
rest = url

# 경로 분리
if "/" in rest:
domain, path = rest.split("/", 1)
path = "/" + path
else:
domain = rest
path = "/"

# 포트 분리
if ":" in domain:
domain, port = domain.split(":")
else:
port = "80" if protocol == "http" else "443"

return {
"프로토콜": protocol,
"도메인": domain,
"포트": port,
"경로": path
}

url = "https://www.example.com:8080/api/users"
result = parse_url(url)

for key, value in result.items():
print(f"{key}: {value}")

유니코드와 인코딩

유니코드 다루기

# 한글
text = "안녕하세요"
print(len(text)) # 5

# 이모지
emoji = "😀🎉"
print(len(emoji)) # 2

# 유니코드 코드 포인트
print(ord("A")) # 65
print(chr(65)) # A
print(ord("가")) # 44032
print(chr(44032)) # 가

인코딩/디코딩

text = "안녕하세요"

# 인코딩 (문자열 → 바이트)
utf8_bytes = text.encode("utf-8")
print(utf8_bytes) # b'\xec\x95\x88\xeb\x85\x95...'

euckr_bytes = text.encode("euc-kr")
print(euckr_bytes)

# 디코딩 (바이트 → 문자열)
decoded = utf8_bytes.decode("utf-8")
print(decoded) # 안녕하세요

자주 묻는 질문

Q1. 문자열은 불변인가요?

A: 네, 문자열은 불변(immutable)입니다.

text = "hello"
# text[0] = "H" # ❌ TypeError

# 새 문자열 생성
text = "H" + text[1:] # ✅ "Hello"

Q2. + vs join, 어떤 게 빠른가요?

A: 많은 문자열 연결 시 join이 빠릅니다.

# ❌ 느림 (많은 문자열 생성)
result = ""
for i in range(1000):
result += str(i)

# ✅ 빠름
result = "".join(str(i) for i in range(1000))

Q3. 멀티라인 문자열에서 들여쓰기는?

A: textwrap 모듈 사용

from textwrap import dedent

text = dedent("""
첫 번째 줄
두 번째 줄
세 번째 줄
""").strip()

print(text)
# 첫 번째 줄
# 두 번째 줄
# 세 번째 줄

Q4. 정규표현식이 필요한가요?

A: 복잡한 패턴 매칭에는 필요합니다.

import re

# 간단한 경우: 문자열 메서드
email = "user@example.com"
if "@" in email and "." in email:
print("이메일 형식")

# 복잡한 경우: 정규표현식
pattern = r"^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$"
if re.match(pattern, email):
print("유효한 이메일")

다음 단계

문자열 처리를 마스터했습니다!

핵심 정리:
✅ 인덱싱과 슬라이싱
✅ 다양한 문자열 메서드
✅ 문자열 포매팅 (f-string)
✅ 검색, 변환, 검증
✅ 실전 활용 예제

다음 단계: 리스트와 튜플에서 컬렉션을 배워보세요!