format — sprintf 스타일 문자열 포매팅

format — sprintf 스타일 문자열 포매팅

숫자나 문자를 정해진 모양으로 깔끔하게 출력하고 싶을 때가 있어요. C의 sprintf처럼 변환 지정자를 써서 문자열을 만드는 Tcl 명령어가 format이에요.

출처: Tcl Built-In Commands — format

본문

시그니처

format formatString ?arg arg ...?

format은 ANSI C sprintf와 비슷하게 형식화된 문자열을 만들어요. formatString이 결과를 어떻게 만들지 지정하는데, sprintf처럼 % 변환 지정자를 사용하고, 추가 인자(있다면)가 결과에 치환될 값을 제공해요. 반환값은 형식화된 문자열이에요.

동작 방식

formatformatString을 왼쪽에서 오른쪽으로 훑어요. %가 아닌 문자는 결과 문자열에 그대로 붙고, %를 만나면 그 뒤의 문자들을 변환 지정자(conversion specifier) 로 해석해요. 변환 지정자는 그다음 차례의 arg를 특정 형식으로 변환하고, 그 결과가 지정자 자리를 대신해 결과 문자열에 들어가요. 지정자가 여럿 있으면 각각이 추가 인자 하나씩을 변환해요. 따라서 formatString에 있는 모든 지정자에 맞는 충분한 인자를 넘겨야 해요.

각 변환 지정자는 최대 여섯 부분으로 이루어져요:

  1. XPG3 위치 지정자% 뒤에 십진수와 $가 오는 형태(%2$d)예요. 이 경우 변환할 값을 다음 순차 인자에서 가져오지 않고 숫자가 가리키는 인자에서 가져와요(1이 첫 번째 인자). 지정자 안에 *가 있어서 여러 인자가 필요하면 그 숫자에서 시작해 연속적으로 사용해요. XPG3 위치 지정 규칙을 따르며, 한 번이라도 위치 지정자를 쓰면 모든 지정자가 위치 지정자여야 해요.
  2. 플래그 집합 — 다음 플래그 문자들을 아무 순서로나 포함할 수 있어요.
    • - — 변환 결과를 필드 안에서 왼쪽 정렬(숫자는 보통 오른쪽 정렬에 앞쪽 공백).
    • + — 양수여도 항상 부호를 붙여 출력.
    • 공백 — 첫 문자가 부호가 아니면 숫자 앞에 공백 하나 추가.
    • 0 — 숫자 왼쪽을 공백 대신 0으로 채움.
    • # — 대체 출력 형태를 요청. o 변환은 첫 자리가 항상 0임을 보장하고, x/X는 결과가 0이 아닐 때 앞에 0x/0X를 붙여요. b0b를 붙여요. 모든 부동소수 변환(e,E,f,g,G)에서는 결과에 항상 소수점이 있음을 보장하고, g/G에서는 끝의 0을 제거하지 않도록 지정해요.
  3. 필드 너비 — 십진수로 된 최소 필드 너비예요. 표 형식 출력에서 열을 맞추는 데 주로 쓰여요. 변환 결과가 최소 너비보다 짧으면 그만큼 채워요. 기본은 왼쪽에 공백을 붙이지만 0- 플래그로 0 채움·오른쪽 채움을 지정할 수 있어요. *로 지정하면 다음 인자(정수여야 함)가 최소 너비를 결정해요.
  4. 정밀도/범위 — 온점 뒤 숫자로 된 정밀도예요. 변환 종류에 따라 의미가 달라져요. e,E,f는 소수점 오른쪽 자릿수, g,G는 소수점 양쪽을 포함한 전체 자릿수, 정수 변환은 출력할 최소 자릿수(필요하면 앞에 0), s는 출력할 최대 문자 수(초과분은 버려짐)를 나타내요. *로 지정하면 다음 인자가 정밀도를 결정해요(숫자 문자열이어야 함).
  5. 크기 수정자ll, h, l 중 하나예요. ll은 정수를 잘라내지 않고 그대로 변환하고, h는 16비트 범위로 잘라 변환하며(거의 쓸 일 없음), lexprwide() 함수가 만드는 범위(최소 64비트)로 잘라 변환해요. hl이 없으면 exprint() 함수 범위(최소 32비트, tcl_platform 배열의 wordSize에 따라 결정)로 잘라요.
  6. 변환 문자(필수) — 변환의 종류를 정하는 알파벳 문자예요.

지원되는 변환 문자:

문자 의미
d 정수를 부호 있는 십진 문자열로 변환
u 정수를 부호 없는 십진 문자열로 변환 (잘림 범위가 없으면 의미가 없어서 ll과 조합 불가)
i d와 동일한 부호 있는 십진
o 정수를 부호 없는 8진 문자열로 변환
x / X 정수를 부호 없는 16진 문자열로 변환 (x0123456789abcdef, X0123456789ABCDEF)
b 정수를 부호 없는 2진 문자열(0과 1)로 변환
c 정수를 그 유니코드 문자로 변환
s 변환 없이 문자열 그대로 삽입
f xx.yyy 형태의 부호 있는 십진 문자열로 변환 (y 개수는 정밀도, 기본 6; 정밀도 0이면 소수점 생략)
e / E x.yyye±zz 형태의 과학 표기 (정밀도 기본 6; E를 쓰면 e 대신 E 출력)
g / G 지수가 -4보다 작거나 정밀도 이상이면 %e/%E로, 그 외엔 %f로 변환. 끝의 0과 소수점은 제거
% 변환 없이 %를 삽입

ANSI sprintf와의 차이

  • Tcl은 항상 유니코드 문자로 처리한다는 점을 보장해요.
  • %p%n 지정자는 지원되지 않아요.
  • %c 변환은 인자가 정수여야 하고 그 값을 대응 문자로 변환해요.
  • 부동소수 값을 포매팅할 때 크기 수정자는 무시돼요.
  • ll 수정자와 b 지정자는 sprintf에 대응이 없어요.

예제

유니코드 숫자 값을 그 문자로 변환해요:

set value 120
set char [format %c $value]

time의 출력을 초 단위로 바꿔 백분의 일 초 정밀도로 출력해요:

set us [lindex [time $someTclCode] 0]
puts [format "%.2f seconds to execute" [expr {$us / 1e6}]]

X11 리터럴 색상 명세를 만들어요 (각 성분은 0..255):

set color [format "#%02x%02x%02x" $r $g $b]

XPG3 형식 코드로 데이터 순서를 바꾸지 않고 필드 순서를 재배치해요(로컬라이즈된 메시지 카탈로그에서 자주 쓰는 기법):

set fmt1 "Today, %d shares in %s were bought at $%.2f each"
puts [format $fmt1 123 "Global BigCorp" 19.37]

set fmt2 "Bought %2\$s equity ($%3$.2f x %1\$d) today"
puts [format $fmt2 123 "Global BigCorp" 19.37]

3의 거듭제곱 작은 표를 출력해요:

set w1 5
set w2 10
set sep +-[string repeat - $w1]-+-[string repeat - $w2]-+
puts $sep
puts [format "| %-*s | %-*s |" $w1 "Index" $w2 "Power"]
puts $sep
set p 1
for {set i 0} {$i<=20} {incr i} {
    puts [format "| %*d | %*ld |" $w1 $i $w2 $p]
    set p [expr {wide($p) * 3}]
}
puts $sep

더 알아보기