문자열 포맷팅
문자열을 포맷팅하는 방법은 아래와 같은 방식이 있습니다.
%format 연산자 (Old Style String Formatting)- 문자열
format()함수 (New Style String Formatting) - 문자열 리터럴 (f-string, Formatted String Literals)
- 템플릿 문자열 (Template Strings)
% Format 연산자
printf 스타일의 포맷팅으로 C 언어에 익숙한 사람들에게 친숙합니다. 문자열 내에 % 기호와 타입 지정자를 사용하여 변수를 삽입합니다.
name = "Alice"
age = 30
print("Name: %s, Age: %d" % (name, age)) # Name: Alice, Age: 30
print('%d, %d, %d' % (1, 2, 3)) # 1, 2, 3
print('이름: %s, 나이: %d, 키: %3.2f' % ("영수", 25, 175.3)) # 이름: 영수, 나이: 25, 키: 175.30
print('%x' % 10) # a
print('%e' % 0.0000123) # 1.230000e-05
% Format 연산자 형식 문자열
| 형식 문자열 | 의미 |
|---|---|
| s | 문자열 |
| d | 십진수 – Int |
| f, F | 실수 – float |
| x, X | 16진수 |
| e, E | 실수를 지수승 형태로 출력 |
문자열 format() 함수
% 연산자의 단점을 보완하기 위해 Python 2.6에서 도입되었습니다.
중괄호 {}를 플레이스홀더로 사용하고, format() 메서드의 인자로 값을 전달합니다.
name = "Alice"
age = 30
price = 19.99
# 1) 위치 인자
message = "이름: {}, 나이: {}, 가격: {:.2f}".format(name, age, price)
print(message)
# 2) 인덱스 인자
message = "나이: {1}, 이름: {0}, 가격: {2:.2f}".format(name, age, price)
print(message)
# 3) 키워드 인자
message = "이름: {n}, 나이: {a}, 가격: {p:.2f}".format(n=name, a=age, p=price)
print(message)
# 출력 (모두 동일): 이름: Alice, 나이: 30, 가격: 19.99
문자열 리터럴 (f-string, Python 3.6 이상)
Python 3.6에서 도입된 가장 현대적이고 강력한 포맷팅 방식입니다.
문자열 앞에 f를 붙이고, 문자열 내부의 {} 안에 직접 변수명이나 파이썬 표현식을 작성합니다.
name = "Alice"
age = 30
price = 19.99
# f-string: { } 안에 직접 변수나 표현식 사용
message = f"이름: {name}, 나이: {age}, 가격: {price:.2f}"
print(message)
# 표현식 사용 예시
x = 10
y = 5
message2 = f"10 + 5 = {x + y}"
print(message2)
# 출력:
# 이름: Alice, 나이: 30, 가격: 19.99
# 10 + 5 = 15
템플릿 문자열 (Template Strings)
string 모듈의 Template 클래스를 사용하는 방식입니다.
주로 보안상의 이유로 사용자 입력을 통해 문자열을 포맷팅해야 할 때 사용됩니다.eval()이나 f-string처럼 임의의 파이썬 코드를 실행할 수 없으므로, 잠재적인 보안 위험을 줄일 수 있습니다.
from string import Template
name = "Alice"
age = 30
# $변수명 또는 ${변수명} 형식으로 플레이스홀더 사용
template_str = Template("이름: $name, 나이: ${age}살")
# 1) substitute() 메서드 사용 (변수가 없으면 KeyError 발생)
message_sub = template_str.substitute(name=name, age=age)
print(message_sub)
# 2) safe_substitute() 메서드 사용 (변수가 없어도 오류 없이 플레이스홀더를 그대로 둠)
template_str_safe = Template("이름: $name, 나이: ${age}살, 직업: $job")
message_safe = template_str_safe.safe_substitute(name=name, age=age)
print(message_safe)
# 출력:
# 이름: Alice, 나이: 30살
# 이름: Alice, 나이: 30살, 직업: $job
파이썬 문자열 포맷팅 방식 비교
| 특징 | % 연산자 (Old Style) | str.format() (New Style) | f-string (Literal String) | string.Template (Template String) |
|---|---|---|---|---|
| 도입 시기 | 초기 버전 (Python 1.0+) | Python 2.6 | Python 3.6 | Python 2.4 (string 모듈) |
| 문법 | "텍스트 %s %d" % (변수, 값) | "텍스트 {} {}".format(변수, 값) | f"텍스트 {변수} {값}" | Template("텍스트 $변수").substitute(...) |
| 가독성 | 낮음 (타입 지정자 기억 필요) | 좋음 (명시적) | 가장 좋음 (직관적) | 좋음 (단순함) |
| 유연성 | 낮음 (순서 고정, 기능 제한) | 좋음 (위치, 인덱스, 키워드) | 매우 좋음 (모든 Python 표현식) | 낮음 (변수명만 가능, 포맷 제한) |
| 성능 | 상대적으로 느림 | 보통 | 가장 빠름 | 보통 (오버헤드 약간 있음) |
| 보안 | 위험 (%s 취약점, 잘못된 포맷) | 보통 | 위험 (임의 코드 실행 가능) | 가장 안전 (임의 코드 실행 불가) |
| 권장 여부 | 비권장 (레거시 코드용) | 유효 (특정 상황에서 사용) | 대부분의 상황에서 권장 | 보안이 중요할 때 (사용자 입력) |
print 함수를 이용한 출력
콘솔 또는 표준 출력 장치에 텍스트나 변수를 출력하는 데 사용되는 기본적인 내장 함수입니다. print 함수는 여러 가지 방식으로 데이터를 출력할 수 있으며, 다양한 옵션을 제공합니다.
print 함수의 기본 사용법
print(*objects, sep=' ', end='\n', file=sys.stdout, flush=False)
- *objects: 출력할 객체들. 여러 객체를 쉼표로 구분하여 전달할 수 있습니다.
- sep (선택적): 여러 객체를 출력할 때 객체들 사이에 삽입할 문자열을 지정합니다. 기본값은 공백(‘ ‘)입니다.
- end (선택적): 출력이 끝난 후 추가할 문자열을 지정합니다. 기본값은 줄바꿈(‘\n’)입니다.
- file (선택적): 출력할 파일이나 파일과 유사한 객체를 지정합니다. 기본값은 sys.stdout(표준 출력)입니다.
- flush (선택적): True로 설정하면 출력 버퍼를 강제로 비웁니다. 기본값은 False입니다.
문자열, 숫자 출력
print("Hello, World!")
# 여러 객체 출력
print("Hello", "World", 123) # Hello World 123
# sep 인수
print("Hello", "World", sep="-") # Hello-World
# end 인수
print("Hello", end="")
print("World")
변수 출력
name = "Alice"
age = 30
print("Name:", name)
print("Age:", age)
input 함수를 이용한 입력
사용자로부터 입력을 받아들일 때 사용되는 내장 함수입니다.
이 함수는 사용자가 입력한 값을 문자열로 반환하며, 기본적으로 콘솔에서 입력을 받습니다.
input 함수의 기본 사용법
variable = input(prompt)
- prompt (선택적): 사용자가 입력할 때 화면에 표시될 문자열입니다. 보통 입력을 유도하는 메시지로 사용됩니다.
- variable: 사용자가 입력한 값을 저장할 변수입니다. 이 값은 항상 문자열로 반환됩니다.
간단한 입력 받기
name = input("Enter your name: ")
print(f"Hello, {name}!")
age = int(input("Enter your age: "))
print(f"You are {age} years old.")
height = float(input("Enter your height in meters: "))
print(f"Your height is {height} meters.")
여러 입력 받기
x, y = input("Enter two numbers separated by space: ").split()
x = int(x)
y = int(y)
print(f"Sum: {x + y}")
리스트로 입력 받기
numbers = input("Enter numbers separated by space: ").split()
numbers = [int(n) for n in numbers]
print(f"Numbers: {numbers}")
파일 출력
파이썬의 print() 함수는 기본적으로 콘솔(화면)에 출력하지만, file 인자를 사용하면 파일에도 직접 출력할 수 있습니다.
이 방법은 여러 개의 변수나 표현식을 한 번에 파일에 쓰고 싶을 때 특히 편리합니다.
print() 함수는 file이라는 선택적 인자에 파일 객체(file object) 를 전달하면 콘솔 대신 해당 파일에 내용을 씁니다.
print(*objects, sep=' ', end='\n', file=sys.stdout, flush=False)
여기서 중요한 인자는 file입니다. 기본값은 sys.stdout (표준 출력, 즉 콘솔)입니다.
- 단계별 예시
- 파일 열기:
open()함수를 사용하여 쓰기 모드('w'또는'a')로 파일 객체를 생성합니다. print()함수 사용:print()함수를 호출할 때,file=파일객체형태로 파일 객체를 지정합니다.- 파일 닫기: 작업이 끝나면
close()메서드를 호출하여 파일 객체를 닫습니다. (가장 좋은 방법은with문을 사용하는 것입니다.)
- 파일 열기:
with 문을 사용하여 print()로 파일에 쓰기
이 방법이 가장 권장되는 방법입니다. with 문이 파일을 자동으로 닫아줍니다.
# 'w' 모드: 파일이 있으면 내용을 지우고 새로 씁니다.
file_name = "print_output.txt"
with open(file_name, "w", encoding='utf-8') as f:
print("안녕하세요, 파일에 출력합니다!", file=f)
name = "파이썬"
age = 3
print(f"이름: {name}, 버전: {age}", file=f)
print("여러 줄도 문제없어요.", file=f)
# print의 sep, end 인자도 그대로 사용 가능
print(1, 2, 3, sep='-', end='.\n', file=f)
print(f"'{file_name}' 파일에 내용이 성공적으로 작성되었습니다.")
# 파일의 내용을 읽어서 확인해볼 수 있습니다.
with open(file_name, "r", encoding='utf-8') as f:
print("\n--- 파일 내용 ---")
print(f.read())
flush 인수
print() 함수의 flush 인자는 출력 버퍼(buffer)와 관련된 중요한 기능을 수행합니다.
기본값은 False이며, True로 설정할 경우 출력 버퍼를 즉시 비우도록 지시합니다.
컴퓨터 시스템은 성능 향상을 위해 대부분의 출력 작업을 버퍼링(buffering) 합니다.
즉, 데이터를 즉시 목적지(화면, 파일 등)로 보내지 않고, 일단 임시 저장 공간(버퍼)에 모아둡니다.
버퍼가 가득 차거나 특정 조건이 되면 모아둔 데이터를 한꺼번에 목적지로 보냅니다.
이 버퍼링 방식은 효율적이지만, 때로는 문제가 될 수 있습니다.
- 실시간 정보 부족: 프로그램 실행 중 실시간으로 특정 출력을 바로 확인해야 할 때, 버퍼링 때문에 지연될 수 있습니다.
- 데이터 손실 위험: 프로그램이 예기치 않게 종료될 경우, 버퍼에 남아있던 데이터가 목적지에 기록되지 못하고 손실될 수 있습니다.
flush=True 인자는 이러한 버퍼링 동작을 무시하고, 현재 버퍼에 있는 데이터를 즉시 목적지로 보내도록(버퍼를 비우도록) 강제합니다.
import time
print("버퍼링 예시:")
print("이 메시지는 바로 출력되지 않을 수 있습니다.", end=' ')
time.sleep(2) # 2초 대기
print("2초 후 출력됩니다.")
print("\nflush=True 사용 예시:")
print("이 메시지는 바로 출력됩니다.", end=' ', flush=True)
time.sleep(2) # 2초 대기
print("2초 후 이 메시지가 출력됩니다.")
이스케이프 시퀀스
프로그래밍 언어에서 특정 문자들을 일반적인 문자의 역할이 아닌 다른 특별한 목적으로 사용하기 위해 정의된 문자 조합입니다.
가장 일반적으로 백슬래시(\) 문자 뒤에 다른 문자가 오는 형태로 사용되며, 문자열 내에서 다음과 같은 목적으로 활용됩니다:
- 눈에 보이지 않는 제어 문자 표현: 줄 바꿈, 탭, 캐리지 리턴 등
- 문자열 구분 기호 표현: 작은따옴표나 큰따옴표가 문자열 안에 포함될 때
- 특정 유니코드 문자 표현: 아스키(ASCII) 범위 밖의 특수 문자나 기호
제어 문자 (Control Characters)
출력 형식이나 문자열 내에서 특정 동작을 수행하기 위해 사용됩니다.
\n(Newline, 개행): 줄을 바꿉니다.
print("Hello\nWorld")
# 출력:
# Hello
# World
\t(Tab, 탭): 수평 탭을 삽입합니다.
print("Name:\tAlice")
# 출력: Name: Alice
\r(Carriage Return, 캐리지 리턴): 커서를 현재 줄의 맨 앞으로 이동시킵니다. (과거 타자기의 줄 시작)
print("Hello\rWorld")
# 출력: World (Hello가 World로 덮어씌워짐)
\b(Backspace, 백스페이스): 커서를 한 칸 뒤로 이동시켜 바로 앞의 문자를 지우는 효과를 냅니다.
print("Hello\b") # Hell 출력 (o가 지워짐)
print("Hello\bWorld") # HellWorld 출력
문자열 구분 기호 (Quote Characters)
문자열을 정의할 때 사용한 따옴표(‘, “)와 동일한 따옴표를 문자열 안에 포함해야 할 경우, 이스케이프 시퀀스를 사용합니다.
- \’ (Single Quote): 작은따옴표를 표현합니다.
- \” (Double Quote): 큰따옴표를 표현합니다.
print('그는 "안녕하세요!"라고 말했다.') # 다른 따옴표를 사용해도 되지만,
print("그는 \"안녕하세요!\"라고 말했다.") # 같은 따옴표를 사용할 경우
# 출력: 그는 "안녕하세요!"라고 말했다.
백슬래시 자체 표현 (Literal Backslash)
이스케이프 문자로 사용되는 백슬래시 자체를 문자열 안에 표현하고 싶을 때는 두 개의 백슬래시(\\)를 사용합니다.
print("경로: C:\\Users\\Public")
# 출력: 경로: C:\Users\Public
유니코드 및 16진수 값 표현 (Unicode and Hexadecimal Values)
특정 유니코드 문자나 16진수 값을 직접 지정하여 문자를 표현할 때 사용됩니다.
\xhh: 16진수 값hh에 해당하는 ASCII/Latin-1 문자.\uHHHH: 16진수 값HHHH에 해당하는 16비트 유니코드 문자.\UHHHHHHHH: 16진수 값HHHHHHHH에 해당하는 32비트 유니코드 문자.
print("\x41") # 16진수 41은 ASCII 'A'
# 출력: A
print("\uAC00") # 유니코드 AC00은 '가'
# 출력: 가
ASCII
ASCII (아스키) 는 American Standard Code for Information Interchange의 약자로, 컴퓨터와 같은 전자기기들이 텍스트 데이터를 표현하기 위해 사용하는 가장 기본적인 문자 인코딩 표준 중 하나입니다.
쉽게 말해, 컴퓨터가 ‘A’라는 글자를 볼 때, 실제로 컴퓨터는 ‘A’라는 글자를 이해하는 것이 아니라, ‘A’에 해당하는 특정 숫자 코드(이진수 형태) 를 처리합니다. 아스키 코드는 이 글자와 숫자 코드 간의 약속 체계입니다.
아스키 코드의 특징
- 7비트 인코딩:
- 초기 아스키 코드는 7비트를 사용하여 문자를 표현했습니다. 즉, 27=128가지의 서로 다른 문자나 기호를 나타낼 수 있었습니다.
- 각 문자는 0부터 127까지의 고유한 정수 값에 매핑됩니다.
- 영문자 중심:
- 미국 표준으로 시작했기 때문에 주로 영어 알파벳(대문자, 소문자), 숫자(0-9), 그리고 기본적인 특수문자(예:
!,@,#,&) 및 제어 문자(예: 엔터, 탭, 백스페이스)를 포함합니다. - 한글, 한자, 아랍어 등 영어가 아닌 다른 언어의 문자들은 아스키 코드로 표현할 수 없습니다.
- 미국 표준으로 시작했기 때문에 주로 영어 알파벳(대문자, 소문자), 숫자(0-9), 그리고 기본적인 특수문자(예:
- 대표적인 코드 값:
- 대문자 A-Z: 65-90
- 소문자 a-z: 97-122
- 숫자 0-9: 48-57
- 공백(Space): 32
- 줄 바꿈(Newline): 10 (
\n)
아래 표는 아스키 코드 중 제어 문자와 확장 아스키 코드를 제외한 부호(영문 자판에 사용되는 부호)를 정리한 것이다.
| 10진수 | 부호 | 10진수 | 부호 | 10진수 | 부호 | 10진수 | 부호 |
|---|---|---|---|---|---|---|---|
| 032 | 공백한칸 | 056 | 8 | 080 | P | 104 | h |
| 033 | ! | 057 | 9 | 081 | Q | 105 | i |
| 034 | “ | 058 | : | 082 | R | 106 | j |
| 035 | # | 059 | ; | 083 | S | 107 | k |
| 036 | $ | 060 | < | 084 | T | 108 | l |
| 037 | % | 061 | = | 085 | U | 109 | m |
| 038 | & | 062 | > | 086 | V | 110 | n |
| 039 | ‘ | 063 | ? | 087 | W | 111 | o |
| 040 | ( | 064 | @ | 088 | X | 112 | p |
| 041 | ) | 065 | A | 089 | Y | 113 | q |
| 042 | * | 066 | B | 090 | Z | 114 | r |
| 043 | + | 067 | C | 091 | [ | 115 | s |
| 044 | , | 068 | D | 092 | |116 | t | |
| 045 | – | 069 | E | 093 | ] | 117 | u |
| 046 | . | 070 | F | 094 | ^ | 118 | v |
| 047 | / | 071 | G | 095 | _ | 119 | w |
| 048 | 0 | 072 | H | 096 | ` | 120 | x |
| 049 | 1 | 073 | I | 097 | a | 121 | y |
| 050 | 2 | 074 | J | 098 | b | 122 | z |
| 051 | 3 | 075 | K | 099 | c | 123 | { |
| 052 | 4 | 076 | L | 100 | d | 124 | | |
| 053 | 5 | 077 | M | 101 | e | 125 | } |
| 054 | 6 | 078 | N | 102 | f | 126 | ~ |
| 055 | 7 | 079 | O | 103 | g |
아스키 코드의 한계와 유니코드의 등장
아스키 코드는 7비트만 사용했기 때문에 다양한 언어의 문자를 표현할 수 없다는 치명적인 한계가 있었습니다.
이를 해결하기 위해 8비트를 사용하는 확장 아스키(Extended ASCII)가 등장했지만, 여전히 전 세계의 모든 문자를 포괄하기에는 역부족이었습니다.
이러한 문제점을 해결하기 위해 등장한 것이 바로 유니코드(Unicode) 입니다.
유니코드는 훨씬 더 많은 비트(예: 16비트, 32비트)를 사용하여 전 세계 거의 모든 언어의 문자를 하나의 통일된 체계로 표현할 수 있도록 만들었습니다.
파이썬과 아스키/유니코드
파이썬 3부터 모든 문자열은 기본적으로 유니코드로 처리됩니다.
따라서 ord('A')와 같이 ord() 함수를 사용하면 해당 문자의 유니코드 값을 반환하며, 아스키 문자의 경우 유니코드 값이 아스키 값과 동일합니다.
print(ord('A')) # 65 (ASCII와 유니코드 값이 동일)
print(ord('가')) # 44032 (유니코드 값)
Raw 문자열 (Raw String) r""
이스케이프 시퀀스의 특수 기능을 사용하고 싶지 않고, 백슬래시를 있는 그대로 문자열로 처리하고 싶을 때 Raw 문자열을 사용할 수 있습니다. 문자열 앞에 r 또는 R을 붙입니다.
주로 파일 경로를 지정할 때 유용합니다.
# 일반 문자열 (이스케이프 시퀀스 처리)
print("C:\new\text.txt")
# 출력: C:
# ew
# ext.txt (여기서 \n과 \t가 해석됨)
# Raw 문자열 (이스케이프 시퀀스 무시)
print(r"C:\new\text.txt")
# 출력: C:\new\text.txt