문자열 조작

문자열 조작 (String Manipulation)

string 라이브러리는 문자열을 다루는 함수들을 제공해요. 루아의 문자열은 불변(immutable)이므로, 모든 함수가 새 문자열을 반환해요 (기존 문자열은 바뀌지 않아요). 이 라이브러리의 함수는 string 테이블의 필드로 접근할 수 있고, 문자열 자체의 메타테이블을 통해 ("...") 처럼 호출할 수도 있어요.

string 테이블은 string 라이브러리에 대응하는 메타테이블을 문자열 타입에 설정하기도 해요. 기본적으로 문자열 값에 #(길이), ..(연결), 인덱싱(s[i])이 가능하도록 동작해요.

string.byte

string.byte (s [, i [, j]])

문자열 s에서 i부터 j까지(기본값 i = 1, j = i)의 문자들의 내부 숫자 코드(바이트 값)를 반환해요. 여러 문자를 주면 여러 개의 코드를 반환해요. 범위를 벗어나면 nil을 반환해요.

print(string.byte("ABC"))      --> 65
print(string.byte("ABC", 1, 3)) --> 65 66 67

string.char

string.char (...)

각 정수 인자를 해당 바이트 코드로 갖는 문자열을 만들어 반환해요.

print(string.char(65, 66, 67))  --> ABC

string.dump

string.dump (function [, strip])

함수 function의 바이너리 표현(바이트코드)을 담은 문자열을 반환해요. 나중에 load로 다시 로드해 실행할 수 있어요. strip이 참이면 불필요한(디버그) 정보를 제거해요. 업밸류가 있는 함수는 로드 시 업밸류가 복원되지 않을 수 있어, 일부 함수는 덤프할 수 없어요.

string.find

string.find (s, pattern [, init [, plain]])

문자열 s에서 패턴 pattern의 첫 번째 일치를 찾아요. 일치하면 시작 인덱스와 끝 인덱스를 반환하고, 없으면 nil을 반환해요. 패턴에 캡처가 있으면 추가로 캡처된 값들을 반환해요.

  • init은 검색 시작 위치(기본값 1, 음수면 뒤에서).
  • plain이 참이면 패턴을 리터럴 문자열로 해석해요 (특수 문자를 그대로).
print(string.find("hello world", "world"))    --> 7 11

string.format

string.format (formatstring, ...)

C의 printf와 유사하게, 형식 문자열 formatstring에 따라 인자들을 형식화한 문자열을 반환해요. 지원되는 지시자는 %c, %d, %i, %o, %u, %x, %X, %e, %E, %f, %g, %G, %q, %s, %% 등이에요.

%q는 루아 소스에 안전하게 포함될 수 있는 형식으로 문자열을 인용해요. %a/%A(16진수 부동소수점), %p(포인터)도 지원돼요.

print(string.format("%d items", 5))     --> 5 items
print(string.format("%5.2f", 3.14159))  -->  3.14
print(string.format("%q", 'say "hi"'))  --> "say \"hi\""

string.gmatch

string.gmatch (s, pattern [, init])

일반 for(for cap in string.gmatch(s, pattern))에 쓸 수 있는 반복자 함수를 반환해요. 반복자 함수는 문자열 s에서 패턴 pattern의 일치를 하나씩 찾아 미리 캡처된 부분(없으면 전체 일치)을 반환해요.

for word in string.gmatch("a b c", "%a+") do
  print(word)   --> a  b  c
end

string.gsub

string.gsub (s, pattern, repl [, n])

문자열 s에서 패턴 pattern의 모든(또는 처음 n개의) 일치를 repl로 바꾼 새 문자열을 반환해요. repl은 문자열, 테이블 또는 함수일 수 있어요.

  • repl이 문자열이면 그 문자열로 치환하고, %1, %2처럼 %n은 n번째 캡처로 치환돼요.
  • repl이 함수면 각 일치마다 캡처들을 인자로 호출하고 그 반환값으로 치환해요.
  • repl이 테이블이면 각 일치의 첫 캡처(없으면 전체 일치)를 키로 조회한 값으로 치환해요.
  • 반환값은 (치환된 문자열, 치환 횟수) 두 개예요.
print(string.gsub("hello world", "o", "0"))   --> hell0 w0rld  2
print(string.gsub("hello", "l", "%1%1"))      --> helllo  2

string.len

string.len (s)

문자열 s의 길이(바이트 수)를 반환해요. #s와 같아요. 공백 문자열은 0이에요.

string.lower

string.lower (s)

문자열 s의 모든 ASCII 대문자를 소문자로 바꾼 새 문자열을 반환해요.

string.match

string.match (s, pattern [, init])

문자열 s에서 패턴 pattern의 첫 일치를 찾아, 캡처된 값(없으면 전체 일치)을 반환해요. 일치가 없으면 nil을 반환해요.

print(string.match("num=42", "(%d+)"))  --> 42
print(string.match("abc", "x"))         --> nil

string.pack

string.pack (fmt, v1, v2, ...)

형식 문자열 fmt에 따라 값들을 이진(binary) 패킹한 문자열을 반환해요. fmt의 각 문자는 필드의 형식(정수 크기, 부호, 실수, 문자열 등)을 나타내요.

print(string.pack("i4", 1000))   -- 4바이트 정수로 패킹

string.packsize

string.packsize (fmt)

형식 fmtstring.pack이 만드는 문자열의 크기를 반환해요 (값 없이 크기만).

string.rep

string.rep (s, n [, sep])

문자열 sn번 반복한 문자열을 반환해요. sep가 주어지면 그 사이에 sep를 넣어요.

print(string.rep("ab", 3))           --> ababab
print(string.rep("x", 3, "-"))       --> x-x-x

string.reverse

string.reverse (s)

문자열 s를 뒤집은 문자열을 반환해요. (멀티바이트 문자나 유니코드 조합에는 주의 — 바이트 단위로 뒤집어요.)

string.sub

string.sub (s, i [, j])

문자열 s에서 i부터 j까지의 부분 문자열을 반환해요. 인덱스는 첫 문자 1부터 세고, 음수면 뒤에서부터 세요. ij보다 크면 빈 문자열을 반환해요.

print(string.sub("hello", 2, 4))   --> ell
print(string.sub("hello", -3))     --> llo

string.unpack

string.unpack (fmt, s [, pos])

형식 fmt에 따라 이진 문자열 s에서 값을 추출해 반환해요. 반환값은 (각 필드 값들..., 다음 읽기 위치)예요. pos가 주어지면 그 위치부터 읽어요.

string.upper

string.upper (s)

문자열 s의 모든 ASCII 소문자를 대문자로 바꾼 새 문자열을 반환해요.

패턴 (Patterns)

루아는 정규 표현식과 유사하지만 더 단순한 패턴 매칭(pattern matching) 을 지원해요. 아래는 주요 패턴 요소예요.

  • 문자 클래스: %a(문자), %c(제어 문자), %d(숫자), %g(공백 제외 인쇄 가능), %l(소문자), %p(구두점), %s(공백), %u(대문자), %w(알파벳/숫자), %x(16진수). 대문자(%A 등)는 보수가에요.
  • 매직 문자: ( ) . % + - * ? [ ^ $ — 특별한 의미를 가져요. 문자 그대로 쓰려면 %로 이스케이프(%., %%).
  • . — 임의의 문자.
  • [...] — 문자 집합(character set). [a-z]는 범위, [^...]는 부정.
  • * — 이전 문자/클래스의 0회 이상 (가장 긴 일치).
  • + — 1회 이상 (가장 긴 일치).
  • - — 0회 이상 (가장 짧은 일치).
  • ? — 0회 또는 1회.
  • ^ — 문자열 시작(패턴 첫 글자일 때) 또는 집합 안에서 부정.
  • $ — 문자열 끝(패턴 마지막 문자일 때).
  • %n — n번째 캡처에 대한 역참조.
  • %bxy — 균형 잡힌 문자열 (x로 시작 y로 끝).
  • %f[set] — 경계 부분(앞 문자가 set에 없고 현재 문자가 set에 있는 위치).
  • 캡처: (pattern) — 일치한 부분을 캡처.
print(string.find("hello", "%l+"))            --> 1 5
print(string.gsub("x=5", "(%w+)=(%w+)", "%2=%1"))  --> 5=x

형식 문자열 for Pack and Unpack

string.pack/string.unpack의 형식 문자열에서 각 문자는 필드를 나타내요. 주요 지시자:

  • b — 부호 있는 char (1바이트), B — 부호 없는 char.
  • h — 2바이트 정수, H — 부호 없는 2바이트 정수.
  • l — 4바이트 정수, L — 부호 없는 4바이트 정수.
  • j — 루아 정수 크기, J — 부호 없는 루아 정수 크기.
  • T — 루아 정수의 절대 크기.
  • f — 단정밀도 실수(4바이트), d — 배정밀도 실수(8바이트), n — 루아 실수 크기.
  • i[n] — 부호 있는 n바이트 정수, I[n] — 부호 없는 n바이트 정수.
  • s[n] — 길이 접두사가 있는 문자열, z — 널 종료 문자열, x — 패딩 바이트, Xop — 정렬.
  • <, >, =, !n — 바이트 순서(리틀/빅 엔디언 등) 지정.

출처: 문자열 조작 (String Manipulation)

본문

패턴 매칭의 성능과 한계

루아 패턴은 정규 표현식만큼 강력하지 않아요. 중첩 없음, 역참조 제한, 백트래킹 부재 같은 한계가 있어요. 복잡한 패턴이 필요하면 고성능을 위해 C 모듈을 작성하는 걸 고려해요. 패턴 매칭은 대부분 O(n) 수준으로 빠르게 동작해요.

문자열 메타테이블

루아는 문자열 타입에 메타테이블을 설정해서, string.<func> 형식의 함수 문자열 메서드 호출(s:sub(2)처럼)을 지원해요. 문자열 값은 인덱싱(s[i])으로 개별 바이트(문자)에 접근할 수 있고, 이는 string.sub(s, i, i)와 같아요.

더 알아보기