Wireframe

Julia 문자열 다루기

Julia에서 문자열은 String 타입으로 정의되어 있으며, 내부적으로 UTF8로 인코딩되는 유니코드 문자열을 지원한다. 문자열은 일련의 유니코드 문자들로 구성되며 불변한 값이다. Julia에서는 String 외에 단일 문자를 표현하는 Char 타입이 존재하며, 리터럴 문법 역시 문자열과 문자가 구분된다. (문자열은 겹따옴표, 단일 문자는 홑따옴표를 사용한다.)

기본 리터럴 문법

"string"과 같이 겹따옴표를 사용한다. 여러 줄에 걸쳐지는 문자열은 """..."""로 둘러쌀 수 있다. 파이썬도 이런 3중 따옴표를 사용하는데, 줄리아가 파이썬과 다른 점은 멀티라인 문자열을 쓸 때 들여쓰기가 생기더라도 닫는 따옴표도 들여쓰기 되어 있다면 그 들여쓰기를 무시한다는 점이다.

str = "Hello, world.\n"
str[begin] # == str[1]
# 'H'
str[1]
# 'H'
str[6]
# ','
str[end]
# '\n'
str[4:8]  # 뒤의 위치까지 포함한다.
# "lo, w"
str[4:4] # 단일 범위는 문자열로 리턴된다.
str[end÷2]
# ','
# ÷ 를 입력하려면 \div를 누르고 탭 키를 누른다.

글자 인덱스, 슬라이스

다른 많은 언어들과 마찬가지로 문자열에서 [ ] 안에 인덱스를 넣어서 해당 위치의 문자를 액세스할 수 있다. 이 때 인덱스 값은 글자 단위가 아니라는 점이 함정이다. 인덱스값은 배열과 마찬가지로 1부터 시작하는 ‘바이트 위치’이다. 따라서 a = "안녕하세요"일 때, a[1]은 ‘안’ 이지만, a[2]는 에러가 난다. (단일 문자의 중간부터 읽으려고 해서 올바른 문자가 나오지 않는다.) 이 부분 관련해서는 아래에서 다시 이야기 하겠다. 하지만 for c in str과 같은 식으로 for 루프를 사용하면 글자당 바이트에 상관없이 안전하게 매 글자에 대해서 루프를 도는 것이 가능하다.

시작인덱스와 끝인덱스는 begin, end라는 키워드를 사용해서 참조하는 것이 가능하다. 줄리아는 파이썬과 달리 음수 인덱스를 지원하지 않지만 s[end], s[end-1]과 같은 표현을 사용해서 뒤에서부터 글자를 찾는 것이 가능하다.

str[s:e]는 주어진 시작과 끝 인덱스를 포함하는 부분으로 문자열의 사본을 생성할 수 있다. 줄리아의 무낮열은 불변타입이기 때문에 어떤 문자의 부분열을 액세스하려 한다면, substr() 함수를 사용하는 것을 추천한다. substr(str, start, end)는 문자열 str에서 start ~ end 구간의 메모리를 참조하여 문자열로 보여주기 때문에 추가적인 메모리 할당이 발생하지 않는다.

문자열 내삽

고정된 문자열과 변수값을 합쳐서 새로운 문자열을 만들 때에는 $ 표현을 쓴다. 문자열 내에서 "Hello, $name"과 같이 $를 앞에 붙인 변수이름을 사용하면 변수의 값을 포함한 문자열이 된다. $( ... ) 표현을 써서 표현식의 결과를 문자열에 내삽하는 것도 가능하다.


문자열 관련 기본 함수

다음은 자주 쓰일 법한 문자열 관련 기본 함수이다. 문자열에 대한 함수는 String이 아닌 AbstractString 타입을 인자로 받는다. 만약 문자열을 인자로 받는 함수를 작성한다면 AbstractString 타입으로 인자를 정의해두면, 커스텀 문자열 타입에 대해서도 작동하는 함수를 만들 수 있다.

  • String(AbstractVector{UInt8}) : 인코딩된 바이트 배열로부터 문자열을 생성한다.
  • length(s) : 문자열의 길이 (글자 수)를 계산한다.
  • sizeof(s) : 문자열의 바이트 수를 리턴한다.
  • ncodeuints(s) : 문자열의 코드 수(바이트 수)를 계산한다. n 이 없는 codeunits() 함수는 문자열의 코드 유닛 타입을 리턴한다.
  • codeunits(s) : 문자열의 각 글자의 코드 유닛 벡터를 리턴한다.
  • eachindex(s) : 문자열에서 유효한 각 글자의 첫 인덱스를 리턴한다.
  • string(s, t, u, v, ...) : 소문자로 시작함에 주의하자. 여러 문자열을 하나로 합친다.
  • join(strings, delim [, last]) : 문자열의 배열을 하나로 합친다.
  • str * ing : 두 문자열을 + 가 아닌 * 를 사용해서 합칠 수 있다. ( str * ' ' * ing * '!' ) 문자열 뿐만 아니라Char와도 더할 수 있다.
  • str ^ 3, repeat(str, n) : * 연산자로 문자열끼리 더하는 것처럼, 문자열과 정수를 ^ 연산자로 곱할 수 있다. (같은 문자열을 반복해서 늘린 새 문자열을 만든다.) repeat() 함수로 같은 연산을 수행할 수 있다.

문자열 조작에 관한 함수

다음 함수들은 문자열에 대한 검사 및 조작과 관련된 함수들이다. 문자열 내에서 특정 부분을 찾거나, 쪼개거나 변형하는 기능을 담당한다.

  • startswith(s, prefix),endswith(s, suffix): 문자열의 처음과 끝이 주어진 조건과 일치하는지 확인한다.
  • first(s, n), last(s, n) : 문자열의 앞과 끝에서 n 글자만큼 얻는다.
  • ascii(s) : 문자열을 String 타입으로 변환하면서 모든 글자가 아스키문자인지 확인한다.
  • uppercase(s), lowercase(s), titlecase(s) : 대소문자를 변환한다.
  • lpad(s, n, p), rapd(s, n, p) : 문자열의 왼쪽/오른쪽에 p를 붙여서 길이 n으로 만들어준다.
  • findfirst(pattern, string) : 문자열에서 주어진 패턴이 매치되는 첫 위치를 구한다.
  • findnext(patter, string, start) : 문자열에서 주어진 위치 이후의 매치되는 위치를 구한다.
  • findlast(pattern, string) : 문자열에서 주어진 패턴이 일치하는 마지막 위치를 구한다.
  • findprev(pattern, string, start) : start를 기준으로 왼쪽에서 패턴이 일치하는 위치를 구한다.
  • contains(haystack, needle) : 문자열 내에 주어진 패턴을 검사한다.
  • occursin(needle, haystack) : 문자열 내에 주어진 패턴이 있는지 검사한다.
  • occursin(haystack) : needel -> occursin(needle, haystack) 이 되는 함수를 생성한다.
  • reverse(s) : 문자열을 뒤집는다.
  • collect(s) : 문자열을 Array{Char} 형식의 배열로 변환한다.
  • split(s, dlm; limit=0, keepemtpy=true) : 문자열을 구분자 기준으로 자른다.
  • join(str, delim, last) : 문자열/문자의 배열을 하나의 문자열로 합친다.
  • rsplit(s, dlm; limit=0, keepemtpy=true): 문자열을 끝에서부터 구분자를 찾아 자른다.
  • strip(str, chars) : 문자열 주변의 공백이나 다른 문자를 제거한다. rstrip(), lstript() 버전도 있다.
  • chop(s; head=0, tail=1) : 문자열의 앞 뒤에서 글자를 잘라낸다. 기본적으로 뒤 한 글자를 자른다.

멀티바이트 문자

한글, 한자 등 ASCII 문자가 아닌 글자를 포함하는 문자열은 바이트 길이와 글자수가 일치하지 않는다. 이 때 str[i]를 사용하면 nonascii 문자에 대해서는 유효하지 않은 인덱스가 존재할 수 있다. 이 경우 깨진 문자를 리턴하지 않고 예외를 일으킨다. 유니코드 문자열에서 이것은 꽤 불편해보일 수 있다. 최근에는 언어를 디자인할 때 유니코드 문자열을 다뤄야 하는 것이 거의 필수적으로 요구되기 때문에, 문자열에서 인덱스로 subscription할 때 글자를 셀 것인지, 바이트를 셀 것인지하는 부분을 결정해야 한다. 파이썬의 경우에는 글자수를 쓰고 있고, 줄리아나 Swift는 바이트를 기준으로 액세스하려 한다. (사실 Swift는 바이트보다는 String.Index라는 개별 문자열에서 각 문자의 시작 바이트를 가리키는 별도의 타입을 정의하고 있다.) 글자 인덱스 기준의 문자열을 효율적이며 간단하게 구현하기는 매우 어렵다. 파이썬에서는 성능보다는 편의성에 중점을 맞춰서 지금의 구현이 되었다고 본다.

멀티바이트 문자를 포함하는 문자열에서 특정한 위치의 글자를 찾기는 조금 번거롭다. 몇 가지 인덱스 관련해서 함수가 있다.

  • firstindex(s) : 첫글자의 인덱스를 리턴한다.
  • lastindex(s) : 마지막 글자의 인덱스를 리턴한다.
  • isvalid(s, i) : 인덱스 i가 올바른 인덱스인지 확인한다.
  • thisind(s, i) : 인덱스 i의 코드 유닛을 포함하는 글자의 인덱스를 리턴한다.
  • nextind(s, i[, n]) : i위치의 다음 글자 인덱스를 찾는다. n 값을 주면 여러 글자를 이동한다.
  • prevind(s, i[, n]) : i위치에서 이전 글자 인덱스를 찾는다. (i가 포함된 글자보다 앞 글자)

몇몇 검사 함수

특정 문자에 대한 검사를 수행하는 함수들이 제공된다. 인자가 c로 표기된것은 Char 타입 문자를 인자로 받는 함수이며, s로 표기한 것은 Char 및문자열을 모두 할 수 있는 함수이다.

  • isascii(s) : 아스키 문자인지 확인한다.
  • iscntrl(c) : 제어문자인지 확인한다.
  • isdigit(c), isnumeric(c), isxdigit(c) : 숫자를 확인
  • isletter(c) : 유니코드에서 ‘Letter’ 카테고리에 속하는 문자인지 확인한다.
  • ispuct(c) : 문장 부호인지 체크
  • islowercase(c), islowercase(c) : 대소문자 체크
  • isprint(c) : 출력가능한 문자인지 체크
  • isspace(c) : 공백 문자인지 체크. 스페이스, 탭, 개행 등

대부분의 검사 함수는 단일 문자에 대해서 검사하므로, 문자열 전체에 검사하기 위해서는 all() 함수를 사용한다. 예를 들어 문자열 전체가 아스키문자인지 확인하려면 all(isascii, string) 과 같이 쓰면 된다.

Exit mobile version