트랙
/
Julia
Julia
/
연습 문제
/
로그 레벨
로그 레벨

로그 레벨

학습 연습 문제

소개

Julia에서 String은 문자들이 순서대로 나열된 것이에요. 매뉴얼에서도 지적하듯이, "물론 진짜 어려움은 문자가 무엇인지 묻기 시작할 때 생겨요."

이런 복잡한 부분은 Chars 개념에서 더 자세히 다루지만, 간단히 말하면 다음과 같아요:

  • Julia의 모든 문자열은 유니코드예요.
  • ASCII에 해당하는 문자열(대소문자 영어 알파벳 A부터 Z, 숫자, 몇 가지 문장 부호)은 다루기 쉬워요.
  • 세계의 다른 대부분 문자 체계도 다루는 것은 가능하지만, 더 신경 써야 해요.

문자열 리터럴

일반적으로 문자열은 큰따옴표 " "로 감싸요. 작은따옴표 ' '는 Chars에만 사용해요.

큰따옴표 세 개 """ """를 사용할 수도 있는데, 이렇게 하면 문자열 안에서 "를 이스케이프 없이 쓸 수 있어요. 더 중요한 점은, 여러 줄 문자열에서 불필요한 들여쓰기가 제거된다는 거예요.

julia> """
       Multiline
       
       """
"Multiline\nString\n"

문자 이스케이프

C 이후의 대부분 언어처럼, Julia는 이스케이프에 백슬래시 \를 사용해요:

  1. 앞의 예시에서 줄바꿈 \n처럼 화면에 출력되지 않는 문자를 입력할 때.
  2. 그렇지 않으면 특별한 의미를 가지게 될 문자를 보호할 때, 예를 들어 \$(아래 참고).

인덱싱

원칙적으로 문자열은 벡터와 똑같이 인덱싱할 수 있어요:

julia> s[1], s[5]
('J', 'a')

"Julia"처럼 ASCII 문자열에는 분명히 잘 동작하지만, 그건 세계 대부분의 언어를 무시하는 셈이에요.

약 15세기 전에 고대 영어로 쓰인 《베오울프》에 나오는 문자 하나를 생각해 봐요.

"Hrōðgār"는 분명히 7개의 문자지만, 그중 전부가 ASCII인 것은 아니에요.

julia> king = "Hrōðgār"
"Hrōðgār"

julia> length(king)
7

julia> isascii(king)
false

# collect() converts to a Char vector:
julia> collect(king)
7-element Vector{Char}:
 'H': ASCII/Unicode U+0048 (category Lu: Letter, uppercase)
 'r': ASCII/Unicode U+0072 (category Ll: Letter, lowercase)
 'ō': Unicode U+014D (category Ll: Letter, lowercase)
 'ð': Unicode U+00F0 (category Ll: Letter, lowercase)
 'g': ASCII/Unicode U+0067 (category Ll: Letter, lowercase)
 'ā': Unicode U+0101 (category Ll: Letter, lowercase)
 'r': ASCII/Unicode U+0072 (category Ll: Letter, lowercase)

이런 문자열을 인덱싱하는 건 처음에는 잘 되지만, 어느 순간 무너져요:

julia> king[3]
'ō': Unicode U+014D (category Ll: Letter, lowercase)

julia> king[4]
ERROR: StringIndexError: invalid index [4], valid nearby indices [3]=>'ō', [5]=>'ð'

문제는 이런 인덱싱이 _바이트_를 세는데, ASCII가 아닌 문자열에서는 바이트와 문자가 1:1 관계가 아니라는 거예요. 유니코드/UTF-8 문자는 표현하는 데 최대 4바이트가 필요할 수 있으며, 이 부분은 Chars 개념에서 더 자세히 살펴봐요.

문자열 만들기

이어 붙이기

많은 언어가 +를 문자열 연결 연산자로 사용하지만, Julia는 아니에요. 적어도 오류 메시지는 친절해요.

julia> "s1 " + "s2"
ERROR: MethodError: no method matching +(::String, ::String)
The function `+` exists, but no method is defined for this combination of argument types.
String concatenation is performed with * 

julia> "s1 " * "s2"
"s1 s2"

The string() 함수는 임의 개수의 문자열을 이어 붙여요.

julia> string("lots ", "of ", "bits")
"lots of bits"

join() 함수도 같은 일을 하고, 문자열 벡터를 받아 주어진 구분자로 이어 붙일 수도 있어요(기본값은 ""예요).

julia> join(["lots", "of", "bits"], "_")
"lots_of_bits"

문자열은 불변이고 이어 붙이기에는 복사가 따른다는 점을 기억해 둬요. 따라서 루프 안에서 이어 붙이기를 반복하는 것은 비효율적이고, 조각들을 벡터에 모아 두었다가 마지막에 한꺼번에 이어 붙이는 게 더 좋아요.

반복

간단해요:

julia> repeat("Abc", 5)
"AbcAbcAbcAbcAbc"

보간

많은 언어가 계산된 값을 문자열에 넣는 방법을 제공하지만, 어떤 문법이 최선인지에는 엄청난 의견 차이가 있어요.

Julia에서는 보간할 값 앞에 $를 붙여요.

julia> myvar = 42
42

julia> "myvar evaluates to $myvar"
"myvar evaluates to 42"

julia> r = 5.3
5.3

julia> "A circle of radius $r has area $(π * r^2)"
"A circle of radius 5.3 has area 88.24733763933729"

괄호를 생략하면 모호해질 때는 괄호가 필요하지만, 공백이 뒤따르는 단일 식별자에는 괄호가 없어도 돼요.

문자열에 $를 포함하려면 \$로 이스케이프해요.

현재 보간으로는 표시할 소수점 자릿수 같은 서식을 지정할 수 없다는 제약이 있다는 점을 기억해 둬요.

@sprintf()

문자열 조립을 더 세밀하게 제어하려고, Julia는 C(그리고 이후의 여러 언어, 위키백과에는 약 30개가 나와요)에서 sprintf 함수를 가져왔어요.

Julia에서는 이것이 Printf 모듈 안의 macro로 구현되어 있어서 @ 접두사가 붙어요.

julia> using Printf

julia> r = 5.3
5.3

julia> @sprintf("A circle of radius %.1f has area %.2f", r, π * r^2)
"A circle of radius 5.3 has area 88.25"

문자열 함수

간단히 하기 위해, 이 절에서는 새 문자열을 반환하고 입력은 그대로 두는 함수들에 집중해요. 많은 함수에는 입력을 제자리에서 수정하는, ! 접미사가 붙은 대응 함수가 있어요.

길이

문자열은 얼마나 길까요? 때로는 무엇을 세느냐에 따라 달라져요.

간단한 경우는 모든 문자가 1바이트를 차지하는 ASCII 문자열이에요.

julia> string_asc = "Julia"
"Julia"

julia> length(string_asc)
5

julia> sizeof(string_asc)
5

length() 함수는 문자 수를 반환하고, sizeof() 함수는 바이트 수를 반환해요.

이 구분은 다른 문자 집합에서는 중요해져요:

julia> king = "Hrōðgār"
"Hrōðgār"

julia> length(king)
7

julia> sizeof(king)
10

분할

프로그래밍에서 흔한 작업은 긴 문자열을 하나 이상의 문자로 된 구분자 문자열을 기준으로 조각조각 나누는 것이에요.

가장 일반적으로는 split() 함수를 사용해요. 구분자는 기본값이 (모든) 공백이지만, 다른 것을 지정할 수도 있어요.

julia> split("my little string")
3-element Vector{SubString{String}}:
 "my"
 "little"
 "string"

julia> split("My_snake_case_string", "_")
4-element Vector{SubString{String}}:
 "My"
 "snake"
 "case"
 "string"

이 예제들은 문자열을 더 작은 _문자열_로 나눠요. 문자열을 _문자_로 나누는 것은 다른 작업이에요.

찾기와 바꾸기

문자열에 지정한 부분 문자열이 들어 있을까요? 이상하게도, 이걸 확인하는 함수가 두 개 있어요. occursin()과 contains()는 인자의 순서만 다를 뿐이에요.

julia> needle = "Julia"
"Julia"

julia> haystack = "Python, Julia and R"
"Python, Julia and R"

julia> occursin(needle, haystack)
true

julia> contains(haystack, needle)
true

위치를 더 구체적으로 확인하려면:

julia> startswith(haystack, "Python")
true

julia> endswith(haystack, "Python")
false

부분 문자열의 시작:끝 인덱스를 구하는 함수는 여러 가지가 있어요:

  • findfirst()
  • findlast()
  • findprev()
  • findnext()
julia> findfirst(needle, haystack)
9:13

부분 문자열을 바꾸려면 x => y 문법으로 바꿀 내용을 나열해요.

julia> replace("abc", "a"=>"b", "b"=>"c", "c"=>"a")
"bca"

Julia 1.7부터 replace 함수는 임의 개수의 변경을 받을 수 있고, 바꾸는 동안 어떤 문자도 두 번 이상 바뀌지 않는다는 것이 보장돼요.

x => y 문법은 pair라고 불리는데, Julia에서 중요한 타입이며 Dicts and Pairs 개념에서 더 자세히 다뤄요.

공백

문자열의 앞과 뒤의 공백을 제거해야 할 때가 자주 있어요.

이를 위한 함수는 lstrip()(왼쪽), rstrip()(오른쪽), strip()(양쪽)이에요.

julia> strip("\n\t  useful_bit\n\n")
"useful_bit"

대소문자 바꾸기

이 함수들의 이름은 대체로 이름만 봐도 알 수 있어요:

julia> s = repeat("aBcD ", 5)
"aBcD aBcD aBcD aBcD aBcD "

julia> uppercase(s)
"ABCD ABCD ABCD ABCD ABCD "

julia> lowercase(s)
"abcd abcd abcd abcd abcd "

julia> titlecase(s)  # Initial letter of each word uppercase
"Abcd Abcd Abcd Abcd Abcd "

지침

이번 연습 문제에서는 로그 줄을 처리해요.

각 로그 줄은 다음과 같은 형식의 문자열이에요: "[<LEVEL>]: <MESSAGE>".

로그 레벨은 세 가지가 있어요:

  • INFO
  • WARNING
  • ERROR

세 가지 과제가 있고, 각 과제에서는 로그 줄 하나를 받아 무언가를 해봐요.

1. 로그 줄에서 메시지 가져오기

message 함수를 구현해서 로그 줄의 메시지를 반환하게 해요:

julia> message("[ERROR]: Invalid operation")
"Invalid operation"

앞뒤의 공백은 제거해야 해요:

julia> message("[WARNING]:  Disk almost full\r\n")
"Disk almost full"

2. 로그 줄에서 로그 레벨 가져오기

log_level 함수를 구현해서 로그 줄의 로그 레벨을 반환하게 해요. 로그 레벨은 소문자로 반환해야 해요:

julia> log_level("[ERROR]: Invalid operation")
"error"

3. 로그 줄 형식 다시 만들기

reformat 함수를 구현해서 로그 줄의 형식을 다시 만들어요. 메시지를 앞에 두고, 그 뒤에 로그 레벨을 괄호 안에 넣어요:

julia> reformat("[INFO]: Operation completed")
"Operation completed (info)"

참고: 이 연습 문제의 모든 문자열은 영어이고 ASCII 문자 집합으로 제한돼요. 이후 콘셉트에서는 유니코드 문자를 다뤄 볼 기회가 있을 거예요.

GitHub에서 편집 링크가 새 창이나 탭에서 열려요
Julia Exercism

로그 레벨 문제를 시작해 볼 준비가 됐나요?

Exercism에 가입하고 Julia 트랙을 개념 35개연습 문제 128개, 그리고 실제 사람의 멘토링과 함께 배우고 익혀 보세요. 모두 무료예요.