오픈 소스 모험: 에피소드 79: Crystal Regular Expression API 탐색

19605 단어 regexrubycrystal
Ruby 정규 표현식 API를 살펴보았습니다. 몇 가지 언어를 더 시도하고 싶은데 가장 확실한 언어는 Crystal입니다.

많은 솔루션이 Ruby에서와 동일하게 작동하지만 일부 차이점은 흥미롭습니다.

테스트 케이스



Crystal에는 %W , which is one of my favorite Ruby features 이 없지만 이 경우 비보간 및 훨씬 덜 멋진 상대%w가 수행됩니다.

테스트 사례는 다음과 같습니다.

%w[
  2015-05-25
  2016/06/26
  27/07/2017
].each do |s|
  p parse_date(s)
end


그리고 예상 결과:

[2015, 5, 25]
[2016, 6, 26]
[2017, 7, 27]


솔루션 1




def parse_date(s)
  case s
  when %r[(\d\d\d\d)-(\d\d)-(\d\d)]
    [$1.to_i, $2.to_i, $3.to_i]
  when %r[(\d\d\d\d)/(\d\d)/(\d\d)]
    [$1.to_i, $2.to_i, $3.to_i]
  when %r[(\d\d)/(\d\d)/(\d\d\d\d)]
    [$3.to_i, $2.to_i, $1.to_i]
  end
end


가장 간단한 솔루션은 변경 없이 Ruby에서와 동일하게 작동합니다.

솔루션 2




#!/usr/bin/env crystal

def parse_date(s)
  case s
  when %r[(\d\d\d\d)-(\d\d)-(\d\d)], %r[(\d\d\d\d)/(\d\d)/(\d\d)]
    [$1.to_i, $2.to_i, $3.to_i]
  when %r[(\d\d)/(\d\d)/(\d\d\d\d)]
    [$3.to_i, $2.to_i, $1.to_i]
  end
end


그룹화when 옵션은 Ruby에서와 동일하게 작동합니다.

해결책 3




def parse_date(s)
  case s
  when %r[(\d\d\d\d)([/-])(\d\d)\2(\d\d)]
    [$1.to_i, $3.to_i, $4.to_i]
  when %r[(\d\d)/(\d\d)/(\d\d\d\d)]
    [$3.to_i, $2.to_i, $1.to_i]
  end
end


역참조도 Ruby에서처럼 작동합니다.

해결책 4



이제 이것은 작동하지 않습니다.

def parse_date(s)
  case s
  when %r[(\d\d\d\d)-(\d\d)-(\d\d)|(\d\d\d\d)/(\d\d)/(\d\d)]
    [($1 || $4).to_i, ($2 || $5).to_i, ($3 || $6).to_i]
  when %r[(\d\d)/(\d\d)/(\d\d\d\d)]
    [$3.to_i, $2.to_i, $1.to_i]
  end
end


그 이유는 Ruby에서 $1String 또는 nil 일 수 있기 때문입니다. Crystal$1에서는 String이므로 일치하지 않으면 액세스하는 오류입니다.

Crystal은 또한 nil 가능한 등가물 $1? , $2? 등을 가지고 있습니다.

def parse_date(s)
  case s
  when %r[(\d\d\d\d)-(\d\d)-(\d\d)|(\d\d\d\d)/(\d\d)/(\d\d)]
    [($1? || $4).to_i, ($2? || $5).to_i, ($3? || $6).to_i]
  when %r[(\d\d)/(\d\d)/(\d\d\d\d)]
    [$3.to_i, $2.to_i, $1.to_i]
  end
end


솔루션 5




def parse_date(s)
  case s
  when %r[(\d\d\d\d)-(\d\d)-(\d\d)|(\d\d\d\d)/(\d\d)/(\d\d)|(\d\d)/(\d\d)/(\d\d\d\d)]
    [($1? || $4? || $9).to_i, ($2? || $5? || $8).to_i, ($3? || $6? || $7).to_i]
  end
end


우리가 아는 것을 알면 동일한 트릭을 사용하여 ?($1 || $4 || $9)로 다시 작성할 수 있습니다.

해결책 6




def parse_date(s)
  case s
  when
    %r[(?<year>\d\d\d\d)-(?<month>\d\d)-(?<day>\d\d)],
    %r[(?<year>\d\d\d\d)/(?<month>\d\d)/(?<day>\d\d)],
    %r[(?<day>\d\d)/(?<month>\d\d)/(?<year>\d\d\d\d)]
    [$~["year"].to_i, $~["month"].to_i, $~["day"].to_i]
  end
end


명명된 캡처 사용은 Ruby 버전과 동일하게 작동합니다.

해결책 7




def parse_date(s)
  case s
  when %r[(?<year>\d\d\d\d)-(?<month>\d\d)-(?<day>\d\d)|(?<year>\d\d\d\d)/(?<month>\d\d)/(?<day>\d\d)|(?<day>\d\d)/(?<month>\d\d)/(?<year>\d\d\d\d)]
    [$~["year"].to_i, $~["month"].to_i, $~["day"].to_i]
  end
end


동일한 이름의 캡처 그룹을 갖는 것은 변경 없이 Ruby에서와 동일하게 작동합니다.

해결책 8




def parse_date(s)
  case s
  when %r[
      (?<year>\d\d\d\d)-(?<month>\d\d)-(?<day>\d\d) |
      (?<year>\d\d\d\d)/(?<month>\d\d)/(?<day>\d\d) |
      (?<day>\d\d)/(?<month>\d\d)/(?<year>\d\d\d\d)
    ]x
    [$~["year"].to_i, $~["month"].to_i, $~["day"].to_i]
  end
end

($1? || $4? || $9) 플래그도 마찬가지입니다. 모든 것이 제대로 작동합니다.

해결책 9




def parse_date(s)
  if %r[
      (?<year>\d\d\d\d)-(?<month>\d\d)-(?<day>\d\d) |
      (?<year>\d\d\d\d)/(?<month>\d\d)/(?<day>\d\d) |
      (?<day>\d\d)/(?<month>\d\d)/(?<year>\d\d\d\d)
    ]x =~ s
    [year.to_i, month.to_i, day.to_i]
  end
end


반면에 이것은 완전히 지원되지 않습니다. 정규식 일치의 유일한 부작용은 //x 변수를 재정의하는 것입니다($~$1 등의 별칭입니다). 정규식 일치는 다른 지역 변수를 재정의할 수 없습니다.

저는 이 Ruby 기능이 그다지 편하지 않기 때문에 여기에서 해당 기능을 찾지 못한 것은 놀라운 일이 아닙니다.

지금까지의 이야기



모든 것이 전혀 또는 최소한의 변경으로 작동했습니다. 이것은 Crystal에 대한 나의 일반적인 경험입니다. 모든 것이 대부분의 시간에 작동합니다.

All the code is on GitHub .

다음에 온다



다음 에피소드에서는 다른 언어가 이 문제를 어떻게 처리하는지 살펴보겠습니다.

좋은 웹페이지 즐겨찾기