Regular Expressions 8

Markdown - Exercism in Elixir

문제 보기 마크다운 파서를 리팩토링하는 문제였다. 다른 문제와 다르게 테스트를 모두 통과하는 코드가 먼저 주어지고, 그것을 테스트를 깨트리지 않으면서 최대한 리팩하는 것이 목표. 괄호로 겹겹이 싸인 코드들이 있어서 우선 파이프라인으로 모두 고쳐주고, 단어 단위로 처리하는 부분을 줄 단위로 처리하도록 수정했다. 대충 스무 줄 정도는 줄인 것 같다. 정규식의 Lookahead, lookbehind 기능의 도움을 크게 받았다. defmodule Markdown do @doc """ Parses a given string with Markdown syntax and returns the associated HTML for that string. ## Examples iex> Markdown.parse("This..

Phone Number - Exercism in Elixir

문제 보기 규칙에 맞게 전화번호 유효성 검증을 하는 문제였다. 지역번호나 국번의 첫 자리가 0이나 1이 아니어야 한다든가 하는 세세한 규칙이 있어 코드가 좀 늘어난 것 빼고는 크게 어렵지는 않았다. 원본 입력 문자열에서 숫자만 취해서 값을 검증하기만 하면 되는 것이 아니라, 자리수를 구분하는 -나 지역번호를 구분하는 ()는 제거하되, 다른 문자가 섞여 있는 것을 찾기 위해 알파벳이나 다른 특수문자는 일시적으로 남겨둬야 한다는 부분이 다소 번거로웠다. defmodule PhoneNumber do @doc """ Remove formatting from a phone number if the given number is valid. Return an error otherwise. """ @spec clean..

Word Count - Exercism in Elixir

문제 보기 주어진 문장의 단어 빈도를 구하는 문제였다. 보통같았으면 공백 기준으로 나눈 뒤 Enum.frequencies/1를 쓰면 금방이었겠지만... 아포스트로피나 하이픈, 일반 알파벳이 아닌 문자(독일어 철자 등...)도 테스트 케이스에 포함되어 있어서, 범용성을 확보하면서 테스트 케이스를 통과시키는 것이 약간 까다로운 문제였다. defmodule WordCount do @doc """ Count the number of words in the sentence. Words are compared case-insensitively. """ @spec count(String.t()) :: map def count(sentence) do regex = ~r/[0-9\pL-']+/iu Regex.sc..

Log Parser - Exercism in Elixir

문제 보기 로그 파싱 예제를 통해 정규식을 배우는 개념 문제였다. 이래저래 시키는 게 많은 개념 문제 치고는 까다로운 부분 없이 간단하게 끝난 것 같다. defmodule LogParser do def valid_line?(line) do Regex.match?(~r/^\[(DEBUG|INFO|WARNING|ERROR)\]/, line) end def split_line(line) do String.split(line, ~r/\/) end def remove_artifacts(line) do String.replace(line, ~r/end-of-line[0-9]+/i, "") end def tag_with_user_name(line) do name = Regex.run(~r/User[\s]+([^\s]..

Isogram - Exercism in Elixir

문제 보기 주어진 문자열이 Isogram인지(중복된 문자가 없는지)를 확인하는 문제였다. 어렵지 않은 문제이기도 해서 한번에 클리어! defmodule Isogram do @doc """ Determines if a word or sentence is an isogram """ @spec isogram?(String.t()) :: boolean def isogram?(sentence) do only_alphabets = sentence |> String.downcase() |> String.replace(~r/[^a-z]/, "") only_alphabets |> String.graphemes() |> Enum.uniq() |> length() |> Kernel.==(String.length(only_a..

ISBN Verifier - Exercism in Elixir

문제 보기 주어진 문자열이 유효한 ISBN에 맞는지 검증하는 문제였다. 길이 확인은 대시(-)만 빼고 하고, 값 검증은 무효한 글자를 모두 제외하고 해야 하는 부분이 약간 까다로웠다. 어렵지는 않고. defmodule IsbnVerifier do @doc """ Checks if a string is a valid ISBN-10 identifier ## Examples iex> IsbnVerifier.isbn?("3-598-21507-X") true iex> IsbnVerifier.isbn?("3-598-2K507-0") false """ @spec isbn?(String.t()) :: boolean def isbn?(isbn) do dash_removed = isbn |> String.replace("..

Run Length Encoding - Exercism in Elixir

문제 보기 개미 수열과 비슷한 식으로, 같은 문자가 여러 개 연속된 것을 짧게 줄이는 간단한 압축-압축 해제 로직을 구현하는 문제였다. Enum.chunk_while/4를 사용하는 방법도 있을 것 같았는데, 익명 함수를 두 개씩 전달하는 것치고 대단하게 도움을 주는 것같지는 않아서 다른 함수들을 조합해서 구현했다. String.split/2의 include_captures 옵션이 제법 쏠쏠하다. defmodule RunLengthEncoder do @spec encode(String.t()) :: String.t() def encode(string) do string |> String.graphemes() |> Enum.chunk_by(fn c -> c end) |> Enum.map(fn [c] -> c..

Date Parser - Exercism in Elixir

문제 보기 정규식에 대한 문제였다. 엘릭서에서 정규식을 어떻게 쓰는지도 문제 후반에 잠깐 다뤄지긴 했지만, 기본적인 정규식 작성법이 조금 더 메인이었던듯. named capture를 써본 적은 별로 없는데(해봐야 순서로 $1, $2 한 정도), 잘 쓰면 되게 좋겠다 싶다. defmodule DateParser do def day(), do: "0?[0-9]{1,2}" def month(), do: "0?[0-9]{1,2}" def year(), do: "[0-9]{4}" def day_names(), do: "(Sun|Mon|Tues|Wednes|Thurs|Fri|Satur)day" def month_names() do "(January|February|March|April|May|June|July|Au..