문자열 조작
문자열 조작 (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)
형식 fmt로 string.pack이 만드는 문자열의 크기를 반환해요 (값 없이 크기만).
string.rep
string.rep (s, n [, sep])
문자열 s를 n번 반복한 문자열을 반환해요. 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부터 세고, 음수면 뒤에서부터 세요. i가 j보다 크면 빈 문자열을 반환해요.
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— 바이트 순서(리틀/빅 엔디언 등) 지정.
본문
패턴 매칭의 성능과 한계
루아 패턴은 정규 표현식만큼 강력하지 않아요. 중첩 없음, 역참조 제한, 백트래킹 부재 같은 한계가 있어요. 복잡한 패턴이 필요하면 고성능을 위해 C 모듈을 작성하는 걸 고려해요. 패턴 매칭은 대부분 O(n) 수준으로 빠르게 동작해요.
문자열 메타테이블
루아는 문자열 타입에 메타테이블을 설정해서, string.<func> 형식의 함수 문자열 메서드 호출(s:sub(2)처럼)을 지원해요. 문자열 값은 인덱싱(s[i])으로 개별 바이트(문자)에 접근할 수 있고, 이는 string.sub(s, i, i)와 같아요.