このページについて
このページは、paiza ラーニング内に開設されているコンテンツ「レベルアップ問題集」で取り扱われているプログラミング課題について、独自の見解を述べたものです。
見解については、paizaラーニングの規約に基づき、許可されている範囲でのみ公開していますが、その内容については paiza とは一切関係なく、また paiza の立場を反映したものではありませんのでご注意ください。
挑戦する課題
レベルアップ問題集の日付セットから「日付のフォーマット (paizaランク C 相当)」を取り上げます。
以下は、問題公開 Web ページからの引用です。
問題
与えらえる文字列が日付のフォーマットに従っているかどうか判定してください。
日付のフォーマットに従った文字列は、次のすべての条件を満たす文字列のことです。
- “YYYY/MM/DD”の形式の10文字からなる
- YYYYは4つの数字からなる
- MMは2つの数字からなり、”01″から”12″の12種類のいずれかである
- DDは2つの数字からなり、”01″から”31″の31種類のいずれかである
入力される値
以下の形式で、文字列Sが1行目で与えらます。
1 |
S |
期待する出力
文字列Sが日付のフォーマットを満たすならば、”Yes”をそうでなければ”No”を1行で出力してください。
条件
すべてのテストケースにおいて、以下の条件を満たします。
- 1 ≦ |S| ≦ 20
- Sは文字列で、|S|はSの長さです。
- Sの各文字は、半角英数字または”/”からなります。
考え方
条件、入力例、出力例から考察すると、次のことがわかる。
- 日付の区切りには必ずスラッシュ( /)が使われている。
- 正しくスラッシュで区切られていれば、数字は3つの部分(年、月、日)に分解できる
- 数字以外に文字列が使われている場合がある。
- 存在しない日付の制限はない(たとえば、2月31日を除外する、という規則は規程されていない)
したがって、アルゴリズムとしては非常に簡単であり、
- 入力された文字列をスラッシュを区切り文字として分解し、各要素を Int 型に変換する
- 要素数が 3 でなければ、正しく分解されていないことになるので、エラーとする。
- 月日の判定には、Swiftのパターンマッチ演算子( ~=)を用いることができる。
という方法を採用できる。
日付の分解であるが、これはよく使っている「文字列を空白で分解し、数値に変換する」という次の構文
1 |
let ia = readLine()!.split(separator: " ").map { Int($0)! } |
を応用することができる。ここで、
separator: として
/ を指定すれば、スラッシュ区切りで年月日に分解することが可能となる。
しかしその一方、スラッシュで分解された文字列が必ずしも数値になるとは限らない。つまり、
Int($0)! という具合に、強制アンラップを行なってしまうと実行時エラーになってしまう可能性が非常に高くなる(数値として表現できる文字列以外を
Int 型のイニシャライザに与えると
nil が戻る、つまり
Int.init() は失敗のあるイニシャライザのため)。
したがって、ここでは Int($0)は強制アンラップは行わず、また map の代わりに compactMap を使うことで、配列から nil を除外することにする。
1 |
let ia = readLine()!.split(separator: "/").compactMap { Int($0) } |
このようにして分解された数値配列の数は 3 つになるはずなので、最初の判定として要素数のカウントを行う。
次に、日付が規程範囲内に収まっているか否かを判定する。この判定にはパターンマッチ演算子(
~=)を利用する。
この演算子は、たとえば変数
a が
1...3 の間に収まっているか否かを判定するために
1 2 3 |
if 1...3 ~= a { // 収まっている } |
のような使い方でパターンマッチを行うことができる。
ただし、気をつけなければいけないのは、パターンマッチ演算子の左側(左辺値)は必ず範囲演算子、右側(右辺値)は変数である、という点である。これが逆になるとコンパイルエラーとなるので注意が必要となる。
解答例
パターンマッチ演算子を使った例は次の通り。
1 2 3 4 5 6 7 8 9 10 |
// スラッシュ区切りで入力文字列を分け、Int にする。その際、Int 型に変換失敗した場合(nil) が含まれる場合にはそれを除去する let ia = readLine()!.split(separator: "/").compactMap { Int($0) } var ans = "No" // パターンマッチ演算子を使って計算 if ia.count == 3 && 1...12 ~= ia[1] && 1...31 ~= ia[2] { ans = "Yes" } print(ans) |