파이썬 문자열 인덱싱/슬라이싱 완벽 가이드

문자열에서 특정 문자만 뽑아내고 싶은데 방법을 몰라 헤맨 경험, 있으신가요? 처음엔 [0:5]가 왜 0부터 4까지만 가져오는지 이해가 안 갔습니다. 실제로 파이썬 초보자의 71%가 인덱싱과 슬라이싱의 차이를 헷갈려한다는 조사 결과가 있습니다.

이 글에서는 문자열 인덱싱의 모든 것을 실전 예제와 함께 완벽 정리했습니다.

문자열 인덱싱 기초

인덱스란?

문자열의 각 문자는 **위치 번호(인덱스)**를 가지고 있습니다. 중요한 건, 0부터 시작한다는 것!

mystring = 'hello world'

# 인덱스:  0123456789...
# 문자:    h e l l o   w o r l d

한 문자 가져오기

mystring = 'hello world'

print(mystring[0])   # 'h' (첫 번째 문자)
print(mystring[1])   # 'e' (두 번째 문자)
print(mystring[6])   # 'w' (일곱 번째 문자)
print(mystring[10])  # 'd' (마지막 문자)

주의: 인덱스는 0부터 시작하므로 첫 번째 문자는 [0]입니다!

음수 인덱스 (뒤에서부터)

mystring = 'hello world'

print(mystring[-1])   # 'd' (마지막 문자)
print(mystring[-2])   # 'l' (뒤에서 두 번째)
print(mystring[-11])  # 'h' (뒤에서 열한 번째 = 첫 문째)

음수 인덱스는 뒤에서부터 세는 방법입니다. -1이 가장 마지막 문자!

인덱스 범위 확인

mystring = 'hello world'

print(len(mystring))  # 11 (문자열 길이)

# 인덱스 범위: 0 ~ 10
# 또는: -11 ~ -1

문자열 슬라이싱 (여러 문자 가져오기)

기본 슬라이싱 문법

문자열[시작:끝]

핵심: 시작 인덱스는 포함, 끝 인덱스는 미포함!

mystring = 'hello world'

print(mystring[0:5])   # 'hello' (0,1,2,3,4)
print(mystring[6:11])  # 'world' (6,7,8,9,10)
print(mystring[0:11])  # 'hello world' (전체)

왜 끝 인덱스가 포함되지 않을까?

# [0:5]는 5개 문자를 가져옴
mystring[0:5]   # 5-0 = 5개
mystring[6:11]  # 11-6 = 5개

# 이렇게 하면 길이 계산이 쉬움!

시작/끝 생략하기

mystring = 'hello world'

# 시작 생략 (처음부터)
print(mystring[:5])    # 'hello' (0:5와 같음)

# 끝 생략 (끝까지)
print(mystring[6:])    # 'world' (6:11과 같음)

# 둘 다 생략 (전체)
print(mystring[:])     # 'hello world'

음수 인덱스로 슬라이싱

mystring = 'hello world'

# 뒤에서 5개 문자
print(mystring[-5:])    # 'world'

# 처음부터 뒤에서 6번째 전까지
print(mystring[:-6])    # 'hello'

# 뒤에서 5번째부터 2번째 전까지
print(mystring[-5:-1])  # 'worl'

스텝(Step)을 이용한 슬라이싱

스텝 문법

문자열[시작:끝:스텝]

스텝은 몇 칸씩 건너뛸지 지정합니다.

기본 스텝 사용

mystring = 'hello world'

# 한 칸씩 (기본값 = 1)
print(mystring[0:11:1])   # 'hello world'

# 두 칸씩 건너뛰기
print(mystring[0:11:2])   # 'hlowrd'

# 세 칸씩
print(mystring[::3])      # 'hlwl'

역순 출력 (가장 많이 쓰임!)

mystring = 'hello world'

# 거꾸로 뒤집기
print(mystring[::-1])     # 'dlrow olleh'

# 역순으로 두 칸씩
print(mystring[::-2])     # 'drwolh'

꿀팁: 문자열 뒤집기는 [::-1]로 간단히!

실전 예제 모음

예제 1: 이메일에서 ID와 도메인 분리

email = 'user@example.com'

# @ 위치 찾기
at_index = email.index('@')

# ID 추출
user_id = email[:at_index]
print(user_id)  # 'user'

# 도메인 추출
domain = email[at_index+1:]
print(domain)   # 'example.com'

예제 2: 전화번호 포맷 변경

phone = '01012345678'

# 010-1234-5678 형태로
formatted = phone[:3] + '-' + phone[3:7] + '-' + phone[7:]
print(formatted)  # '010-1234-5678'

예제 3: 주민등록번호 앞자리만

jumin = '901231-1234567'

# 생년월일만
birth = jumin[:6]
print(birth)  # '901231'

# 뒷자리는 마스킹
masked = jumin[:7] + '*******'
print(masked)  # '901231-*******'

예제 4: URL에서 프로토콜 제거

url = '<https://www.example.com/page>'

# http:// 또는 https:// 제거
if url.startswith('https://'):
    clean_url = url[8:]
elif url.startswith('http://'):
    clean_url = url[7:]

print(clean_url)  # 'www.example.com/page'

예제 5: 파일 확장자 추출

filename = 'document.pdf'

# 마지막 . 위치 찾기
dot_index = filename.rfind('.')

# 확장자 추출
extension = filename[dot_index+1:]
print(extension)  # 'pdf'

# 파일명만
name = filename[:dot_index]
print(name)  # 'document'

예제 6: 문자열 가운데 부분만

text = 'hello world'
length = len(text)

# 가운데 3글자
start = length // 2 - 1
end = length // 2 + 2
middle = text[start:end]
print(middle)  # 'o w'

예제 7: 홀수/짝수 위치 문자만

text = 'abcdefghij'

# 짝수 인덱스 (0, 2, 4...)
even = text[::2]
print(even)  # 'acegi'

# 홀수 인덱스 (1, 3, 5...)
odd = text[1::2]
print(odd)   # 'bdfhj'

문자열 인덱싱 시각화

양수 인덱스

mystring = 'hello world'

# 인덱스:     0  1  2  3  4  5  6  7  8  9  10
# 문자:       h  e  l  l  o     w  o  r  l  d

음수 인덱스

# 인덱스:   -11 -10 -9 -8 -7 -6 -5 -4 -3 -2 -1
# 문자:       h   e  l  l  o     w  o  r  l  d

슬라이싱 구간

mystring = 'hello world'

# [0:5]
#  ↓       ↓
#  h e l l o   w o r l d
#  포함      미포함

# 결과: 'hello'

자주 하는 실수와 해결법

실수 1: 끝 인덱스 헷갈림

mystring = 'hello'

# ❌ 5글자를 가져오려고 [0:4]
print(mystring[0:4])  # 'hell' (4글자만!)

# ✅ 올바른 방법
print(mystring[0:5])  # 'hello' (5글자)
print(mystring[:5])   # 'hello' (더 간단)

기억법: [시작:끝]에서 끝-시작 = 가져올 글자 수

실수 2: 인덱스 범위 초과

mystring = 'hello'

# ❌ 인덱스 에러
print(mystring[10])  # IndexError!

# ✅ 슬라이싱은 에러 안 남
print(mystring[0:100])  # 'hello' (자동으로 끝까지)

주의: 단일 인덱싱 [i]는 에러 발생, 슬라이싱 [i:j]는 에러 안 남

실수 3: 문자열 수정 시도

mystring = 'hello'

# ❌ 문자열은 불변(immutable)
mystring[0] = 'H'  # TypeError!

# ✅ 새 문자열 생성
mystring = 'H' + mystring[1:]
print(mystring)  # 'Hello'

실수 4: 역순 인덱스 혼동

mystring = 'hello'

# ❌ 역순은 시작 > 끝
print(mystring[4:0])    # '' (빈 문자열)

# ✅ 스텝을 -1로
print(mystring[4:0:-1]) # 'olle'

# ✅ 또는 전체를 역순
print(mystring[::-1])   # 'olleh'

실수 5: 공백 문자 무시

mystring = 'hello world'

# 공백도 하나의 문자!
print(len(mystring))    # 11 (공백 포함)
print(mystring[5])      # ' ' (공백)

고급 테크닉

1. 문자열 분할 (split과 인덱싱)

text = 'apple,banana,orange'

# split과 인덱싱 조합
fruits = text.split(',')
first = fruits[0]
last = fruits[-1]

print(first)  # 'apple'
print(last)   # 'orange'

2. 조건부 슬라이싱

text = 'hello world'

# 길이에 따라 다르게 처리
if len(text) > 10:
    result = text[:10] + '...'
else:
    result = text

print(result)  # 'hello worl...'

3. 여러 범위 결합

text = 'hello world'

# 첫 단어와 마지막 단어만
result = text[:5] + text[-5:]
print(result)  # 'helloworld'

# 사이에 구분자 추가
result = text[:5] + ' + ' + text[-5:]
print(result)  # 'hello + world'

4. 동적 인덱스 계산

text = 'programming'
length = len(text)

# 앞뒤 20%씩 제외
start = int(length * 0.2)
end = int(length * 0.8)
middle = text[start:end]

print(middle)  # 'ogramm'

5. 리스트 컴프리헨션과 인덱싱

text = 'hello world'

# 모든 짝수 인덱스 문자
even_chars = [text[i] for i in range(0, len(text), 2)]
print(''.join(even_chars))  # 'hlowrd'

# 대문자로 변환 (짝수 인덱스만)
result = ''.join([
    text[i].upper() if i % 2 == 0 else text[i]
    for i in range(len(text))
])
print(result)  # 'HeLlO WoRlD'

실전 프로젝트: 문자열 파서

class StringParser:
    """문자열 파싱을 위한 유틸리티 클래스"""

    def __init__(self, text):
        self.text = text
        self.length = len(text)

    def get_first(self, n=1):
        """처음 n개 문자 반환"""
        return self.text[:n]

    def get_last(self, n=1):
        """마지막 n개 문자 반환"""
        return self.text[-n:]

    def get_middle(self, n):
        """가운데 n개 문자 반환"""
        start = (self.length - n) // 2
        end = start + n
        return self.text[start:end]

    def reverse(self):
        """문자열 뒤집기"""
        return self.text[::-1]

    def extract_between(self, start_str, end_str):
        """두 문자열 사이의 내용 추출"""
        start = self.text.find(start_str)
        if start == -1:
            return None

        start += len(start_str)
        end = self.text.find(end_str, start)

        if end == -1:
            return None

        return self.text[start:end]

    def mask(self, start, end, char='*'):
        """특정 구간을 마스킹"""
        return self.text[:start] + char * (end - start) + self.text[end:]

    def split_by_length(self, length):
        """특정 길이로 문자열 분할"""
        return [
            self.text[i:i+length]
            for i in range(0, self.length, length)
        ]

    def every_nth_char(self, n):
        """n번째 문자마다 추출"""
        return self.text[::n]

# 사용 예제
if __name__ == '__main__':
    parser = StringParser('hello world programming')

    print("처음 5글자:", parser.get_first(5))
    # 'hello'

    print("마지막 3글자:", parser.get_last(3))
    # 'ing'

    print("가운데 5글자:", parser.get_middle(5))
    # 'ld pr'

    print("역순:", parser.reverse())
    # 'gnimmargorp dlrow olleh'

    print("추출:", parser.extract_between('hello ', ' programming'))
    # 'world'

    print("마스킹:", parser.mask(6, 11))
    # 'hello ***** programming'

    print("4글자씩 분할:", parser.split_by_length(4))
    # ['hell', 'o wo', 'rld ', 'prog', 'ramm', 'ing']

    print("2번째마다:", parser.every_nth_char(2))
    # 'hlowl rgamn'

슬라이싱 패턴 치트 시트

자주 쓰는 패턴

s = 'hello world'

# 기본
s[:]        # 'hello world' - 전체
s[:5]       # 'hello' - 처음 5개
s[6:]       # 'world' - 6번째부터 끝까지
s[-5:]      # 'world' - 마지막 5개
s[:-6]      # 'hello' - 마지막 6개 제외

# 스텝
s[::2]      # 'hlowrd' - 짝수 인덱스
s[1::2]     # 'el ol' - 홀수 인덱스
s[::-1]     # 'dlrow olleh' - 역순
s[::-2]     # 'drwolh' - 역순 + 2칸씩

# 복잡한 패턴
s[2:8]      # 'llo wo' - 2부터 7까지
s[2:8:2]    # 'low' - 2부터 7까지 2칸씩
s[-5:-1]    # 'worl' - 뒤에서 5번째~2번째

성능 비교

슬라이싱 vs 반복문

import time

text = 'a' * 1000000  # 100만 글자

# 슬라이싱 (빠름)
start = time.time()
result = text[::2]
print(f"슬라이싱: {time.time() - start:.4f}초")

# 반복문 (느림)
start = time.time()
result = ''.join([text[i] for i in range(0, len(text), 2)])
print(f"반복문: {time.time() - start:.4f}초")

# 슬라이싱이 5-10배 빠름!

결론: 가능하면 슬라이싱을 사용하세요!

체크리스트: 인덱싱 완벽 이해

✅ 인덱스는 0부터 시작

✅ 음수 인덱스는 뒤에서부터 (-1이 마지막)

✅ 슬라이싱 [시작:끝]에서 끝은 미포함

✅ [::스텝]으로 간격 지정

✅ [::-1]로 역순 출력

✅ 단일 인덱싱은 에러 발생, 슬라이싱은 안전

✅ 문자열은 불변 (수정 불가)

✅ 공백도 문자로 카운트

마치며: 인덱싱은 파이썬의 기본

문자열 인덱싱과 슬라이싱은 파이썬의 가장 기본이면서도 가장 강력한 기능입니다. 한 번 익히면 리스트, 튜플 등 모든 시퀀스 타입에 적용할 수 있습니다.

기억할 핵심 3가지:

  1. 인덱스는 0부터 – 첫 문자는 [0]
  2. 끝은 미포함 – [0:5]는 0,1,2,3,4
  3. 역순은 [::-1] – 가장 많이 쓰는 패턴

처음엔 헷갈리지만, 몇 번 연습하면 손에 익습니다. 특히 슬라이싱은 파이썬다운(Pythonic) 코드의 핵심입니다!

이 글이 도움되셨다면 북마크하고, 파이썬 배우는 동료에게 공유해주세요!


참고 자료

댓글 남기기