From 2d83f8ae0f66372c60daf6416a259b2c4fe8affb Mon Sep 17 00:00:00 2001 From: Bobby Towers Date: Tue, 7 Jun 2022 16:10:21 -0700 Subject: [PATCH 1/4] add exercise docs --- .gitignore | 1 + exercises/concept/date-parser/.docs/hints.md | 57 ++++ .../concept/date-parser/.docs/instructions.md | 13 +- .../concept/date-parser/.docs/introduction.md | 84 ++++++ .../concept/date-parser/src/date_parser.clj | 64 +++- .../date-parser/test/date_parser_test.clj | 273 ++++++++++-------- 6 files changed, 361 insertions(+), 131 deletions(-) diff --git a/.gitignore b/.gitignore index 51a74af27..4acc8d52b 100644 --- a/.gitignore +++ b/.gitignore @@ -21,3 +21,4 @@ pom.xml.asc .clj-kondo .lsp *.calva +*.cpcache diff --git a/exercises/concept/date-parser/.docs/hints.md b/exercises/concept/date-parser/.docs/hints.md index e69de29bb..c37f7845e 100644 --- a/exercises/concept/date-parser/.docs/hints.md +++ b/exercises/concept/date-parser/.docs/hints.md @@ -0,0 +1,57 @@ +# Hints + +## General + +- Review regular expression patterns from the introduction. Remember, when creating the pattern from a string, you must escape some characters. +- Refer to the full [Java regex spec][java-util-regex-pattern]. +- Check out this website about regular expressions: [Regular-Expressions.info][website-regex-info]. +- Check out this website about regular expressions: [Rex Egg -The world's most tyrannosauical regex tutorial][website-rexegg]. +- Check out this website about regular expressions: [RegexOne - Learn Regular Expressions with simple, interactive exercises.][website-regexone]. +- Check out this website about regular expressions: [Regular Expressions 101 - an online regex sandbox][website-regex-101]. +- Check out this website about regular expressions: [RegExr - an online regex sandbox][website-regexr]. + +## 1. Match the day, month, and year from a date + +- Remember to return a string representing the regular expression pattern. +- Review how to create _character classes_ or use _shorthand character classes_. +- Review _quantifiers_. +- A day is one or two digits. +- A month is one or two digits. +- A year is four digits. +- Create a regex pattern with [`re-pattern`][re-pattern]. +- Return a regex match with [`re-matches`][re-matches]. + +## 2. Match the day of the week and the month of the year + +- Review how to write a pattern to match _string literals_. +- Review _alternations_. +- Wrap the whole expression in a _group_. + +## 3. Capture the day, month, and year + +- Review how to write patterns for captures and named captures. +- Reuse the `day`, `month`, `year`, `day-names`, and `month-names` functions that you already implemented. +- You can use [`re-matcher`][re-matcher] to return an instance of `java.util.regex.Matcher` to use with [`re-find`][re-find]. + +## 4. Combine the captures to capture the whole date + +- Remember, string concatenation may be used to join strings. +- Reuse the `capture-day`, `capture-month`, `capture-year`, `capture-day-name`, and `capture-month-name` functions that you already implemented. + +## 5. Narrow the capture to match only on the date + +- Remember, _anchors_ help to match the pattern to the **whole line**. +- String concatenation may be used in a call to `re-pattern`. +- Reuse the `capture-numeric-date`, `capture-month-name-date`, and `capture-day-month-nam-date` functions that you already implemented. + +[java-util-regex-pattern]: https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/regex/Pattern.html +[re-find]: https://clojuredocs.org/clojure.core/re-find +[re-matcher]: https://clojuredocs.org/clojure.core/re-matcher +[re-matches]: https://clojuredocs.org/clojure.core/re-matches +[re-pattern]: https://clojuredocs.org/clojure.core/re-pattern +[website-regex-info]: https://www.regular-expressions.info +[website-rexegg]: https://www.rexegg.com/ +[website-regexone]: https://regexone.com/ +[website-regex-101]: https://regex101.com/ +[website-regexr]: https://regexr.com/ +[website-regex-crossword]: https://regexcrossword.com/ diff --git a/exercises/concept/date-parser/.docs/instructions.md b/exercises/concept/date-parser/.docs/instructions.md index 713c9ebce..6b20578d8 100644 --- a/exercises/concept/date-parser/.docs/instructions.md +++ b/exercises/concept/date-parser/.docs/instructions.md @@ -34,7 +34,7 @@ Implement `day-name` and `month-name` to return a string pattern which, when exe ## 3. Capture the day, month, and year -Implement `capture-day`, `capture-month`, `capture-year`, `capture-day-name`, `capture-month-name` to return a map of the respective components to the names: `"day"`, `"month"`, `"year"`, `"day-name"`, `"month-name"` +Implement `capture-day`, `capture-month`, `capture-year`, `capture-day-name`, and `capture-month-name` to return a map of the respective components to the names: `"day"`, `"month"`, `"year"`, `"day-name"`, and `"month-name"`. ```clojure (capture-month-name "December") @@ -49,3 +49,14 @@ Implement `capture-numeric-date`, `capture-month-name-date`, and `capture-day-mo (capture-numeric-date "01/01/1970") ;;=> {:day "01", :month "01", :year "1970"} ``` + +## 5. Narrow the capture to match only on the date + +Implement `match-numeric-date`, `match-month-name-date`, and `match-day-month-name-date` to return a `java.util.regex.Pattern` that only matches the date, and which can also capture the components. + +```clojure +(re-matches date-parser/match-day-month-name-date "Thursday, January 1, 1970 was the day") +;; => nil +(re-matches date-parser/match-day-month-name-date "Thursday, January 1, 1970") +;; => ["Thursday, January 1, 1970" "Thursday" "January" "1" "1970"] +``` \ No newline at end of file diff --git a/exercises/concept/date-parser/.docs/introduction.md b/exercises/concept/date-parser/.docs/introduction.md index e69de29bb..af7d586ce 100644 --- a/exercises/concept/date-parser/.docs/introduction.md +++ b/exercises/concept/date-parser/.docs/introduction.md @@ -0,0 +1,84 @@ +# Introduction + +## Regular Expressions + +Regular expressions (regex) are a powerful tool for working with strings in Clojure. Regular expressions in Clojure follow the Java specification. String patterns representing the regular expression's meaning are first compiled then used for matching all or part of a string. + +In Clojure, the most concise way to create regular expressions is using the #"pattern" syntax. This provides _syntactic sugar_ as a convenience. To match a _string literal_, we can use this. + +```clojure +#"test" +``` + +If you want to construct a regex pattern dynamically at run time, then you need to use `re-pattern` to convert a string to a pattern that can be used for matching. When doing so, you need to escape every `\` character with another `\`. But if your pattern is one you write into the source code, it is more convenient to use the #"pattern" syntax. + +### Character classes + +Matching a range of characters using square brackets `[]` defines a _character class_. This will match any one character to the characters in the class. You can also specify a range of characters like `a-z`, as long as the start and end represent a contiguous range of code points. + +```clojure +(def regex #"[a-z][ADKZ][0-9][!?]") +(re-matches regex "jZ5!") +;; => "jZ5!" +(re-matches regex "jB5?") +;; => nil +``` + +_Shorthand character classes_ make the pattern more concise. For example: + +- `\d` short for `[0-9]` (any digit) +- `\w` short for `[A-Za-z0-9_]` (any 'word' character) +- `\s` short for `[ \t\n\x0B\f\r]` (any whitespace character) + +When a _shorthand character class_ is used outside of the #"pattern" syntax, it must be escaped: `"\\d"` + +### Alternations + +_Alternations_ use `|` as a special character to denote matching one _or_ another + +```clojure +(def regex #"cat|bat") +(re-matches regex "bat") +;; => "bat" +(re-matches regex "bat") +;; => "cat" +``` + +### Quantifiers + +_Quantifiers_ allow for a repeating pattern in the regex. They affect the group preceding the quantifier. + +- `{N, M}` where `N` is the minimum number of repetitions, and `M` is the maximum +- `{N,}` match `N` or more repetitions +- `{0,}` may also be written as `*`: match zero-or-more repetitions +- `{1,}` may also be written as `+`: match one-or-more repetitions + +### Groups + +Round brackets `()` are used to denote _groups_ and _captures_. The group may also be _captured_ in some instances to be returned for use. In Clojure, these may be named or un-named. Captures are named by appending `?` after the opening parenthesis. Groups function as a single unit, like when followed by _quantifiers_. + +```clojure +(re-find #"(?b)" "blueberry") +;; => ["b" "b"] +``` + +### Anchors + +_Anchors_ are used to tie the regular expression to the beginning or end of the string to be matched: + +- `^` anchors to the beginning of the string +- `$` anchors to the end of the string + +### Concatenation + +Because the `#"pattern"` syntax is a shortcut for `re-pattern`, you may also use string concatenation to dynamically build a regular expression pattern: + +```clojure +(def anchor "$") +(def regex (str "end of the line" anchor)) +(re-matches regex "end of the line?") +;; => nil +(re-matches regex "end of the line") +"end of the line" =~ regex +;; => "end of the line" +``` \ No newline at end of file diff --git a/exercises/concept/date-parser/src/date_parser.clj b/exercises/concept/date-parser/src/date_parser.clj index 447b1a2f3..e7d5d3ba0 100644 --- a/exercises/concept/date-parser/src/date_parser.clj +++ b/exercises/concept/date-parser/src/date_parser.clj @@ -1,39 +1,73 @@ (ns date-parser) -(def day) -(def month) -(def year) +(def day "\\d{1,2}") +(def month "\\d{1,2}") +(def year "\\d{4}") -(def days) +(re-matches #"\d{1,}" "0") + +(def days "Sunday|Monday|Tuesday|Wednesday|Thursday|Friday|Saturday") (defn day-names [s] - ) + (re-matches (re-pattern days) s)) -(def months) +(def months "January|February|March|April|May|June|July|August|September|October|November|December") (defn month-names [s] - ) + (re-matches (re-pattern months) s)) (defn capture-month [s] - ) + (let [matcher (re-matcher (re-pattern (str "(?" month ")")) s)] + (when (.matches matcher) + {:month (.group matcher "month")}))) + +(def anchor "$") +(def regex (re-pattern (str "end of the line" anchor))) +(re-matches regex "end of the line") (defn capture-day [s] - ) + (let [matcher (re-matcher (re-pattern (str "(?" day ")")) s)] + (when (.matches matcher) + {:day (.group matcher "day")}))) (defn capture-year [s] - ) + (let [matcher (re-matcher (re-pattern (str "(?" year ")")) s)] + (when (.matches matcher) + {:year (.group matcher "year")}))) (defn capture-month-name [s] - ) + {:month-name (first (re-find (re-pattern (str "(?" months ")")) s))}) (defn capture-day-name [s] - ) + {:day-name (first (re-find (re-pattern (str "(?" days ")")) s))}) (defn capture-numeric-date [s] - ) + (let [matcher (re-matcher (re-pattern (str "(?" day ")/(?" month ")/(?" year ")")) s)] + (when (.matches matcher) + {:day (.group matcher "day") + :month (.group matcher "month") + :year (.group matcher "year")}))) (defn capture-month-name-date [s] - ) + (let [matcher (re-matcher (re-pattern (str "(?" months ") (?" day "), (?" year ")")) s)] + (when (.matches matcher) + {:month-name (.group matcher "month") + :day (.group matcher "day") + :year (.group matcher "year")}))) (defn capture-day-month-name-date [s] - ) + (let [matcher (re-matcher (re-pattern (str "(?" days "), (?" months ") (?" day "), (?" year ")")) s)] + (when (.matches matcher) + {:day-name (.group matcher "dayname") + :month-name (.group matcher "month") + :day (.group matcher "day") + :year (.group matcher "year")}))) + +(def match-numeric-date + (re-pattern (str "(?" day ")/(?" month ")/(?" year ")"))) + +(def match-month-name-date + (re-pattern (str "(?" months ") (?" day "), (?" year ")"))) + +(def match-day-month-name-date + (re-pattern (str "(?" days "), (?" months ") (?" day "), (?" year ")"))) diff --git a/exercises/concept/date-parser/test/date_parser_test.clj b/exercises/concept/date-parser/test/date_parser_test.clj index 0ff3d34c1..2a9f25cb9 100644 --- a/exercises/concept/date-parser/test/date_parser_test.clj +++ b/exercises/concept/date-parser/test/date_parser_test.clj @@ -1,228 +1,271 @@ (ns date-parser-test (:require [clojure.test :refer [deftest testing is]] - exercism.date-parser)) + date-parser)) (deftest day-test (testing "numeric pattern for day matches" (testing "un-padded 1" - (is (= "1" (re-matches (re-pattern exercism.date-parser/day) "1")))) + (is (= "1" (re-matches (re-pattern date-parser/day) "1")))) (testing "un-padded 2" - (is (= "2" (re-matches (re-pattern exercism.date-parser/day) "2")))) + (is (= "2" (re-matches (re-pattern date-parser/day) "2")))) (testing "un-padded 3" - (is (= "3" (re-matches (re-pattern exercism.date-parser/day) "3")))) + (is (= "3" (re-matches (re-pattern date-parser/day) "3")))) (testing "un-padded 4" - (is (= "4" (re-matches (re-pattern exercism.date-parser/day) "4")))) + (is (= "4" (re-matches (re-pattern date-parser/day) "4")))) (testing "un-padded 5" - (is (= "5" (re-matches (re-pattern exercism.date-parser/day) "5")))) + (is (= "5" (re-matches (re-pattern date-parser/day) "5")))) (testing "un-padded 6" - (is (= "6" (re-matches (re-pattern exercism.date-parser/day) "6")))) + (is (= "6" (re-matches (re-pattern date-parser/day) "6")))) (testing "un-padded 7" - (is (= "7" (re-matches (re-pattern exercism.date-parser/day) "7")))) + (is (= "7" (re-matches (re-pattern date-parser/day) "7")))) (testing "un-padded 8" - (is (= "8" (re-matches (re-pattern exercism.date-parser/day) "8")))) + (is (= "8" (re-matches (re-pattern date-parser/day) "8")))) (testing "un-padded 9" - (is (= "9" (re-matches (re-pattern exercism.date-parser/day) "9")))) + (is (= "9" (re-matches (re-pattern date-parser/day) "9")))) (testing "un-padded 10" - (is (= "10" (re-matches (re-pattern exercism.date-parser/day) "10")))) + (is (= "10" (re-matches (re-pattern date-parser/day) "10")))) (testing "un-padded 11" - (is (= "11" (re-matches (re-pattern exercism.date-parser/day) "11")))) + (is (= "11" (re-matches (re-pattern date-parser/day) "11")))) (testing "un-padded 12" - (is (= "12" (re-matches (re-pattern exercism.date-parser/day) "12")))) + (is (= "12" (re-matches (re-pattern date-parser/day) "12")))) (testing "un-padded 13" - (is (= "13" (re-matches (re-pattern exercism.date-parser/day) "13")))) + (is (= "13" (re-matches (re-pattern date-parser/day) "13")))) (testing "un-padded 14" - (is (= "14" (re-matches (re-pattern exercism.date-parser/day) "14")))) + (is (= "14" (re-matches (re-pattern date-parser/day) "14")))) (testing "un-padded 15" - (is (= "15" (re-matches (re-pattern exercism.date-parser/day) "15")))) + (is (= "15" (re-matches (re-pattern date-parser/day) "15")))) (testing "un-padded 16" - (is (= "16" (re-matches (re-pattern exercism.date-parser/day) "16")))) + (is (= "16" (re-matches (re-pattern date-parser/day) "16")))) (testing "un-padded 17" - (is (= "17" (re-matches (re-pattern exercism.date-parser/day) "17")))) + (is (= "17" (re-matches (re-pattern date-parser/day) "17")))) (testing "un-padded 18" - (is (= "18" (re-matches (re-pattern exercism.date-parser/day) "18")))) + (is (= "18" (re-matches (re-pattern date-parser/day) "18")))) (testing "un-padded 19" - (is (= "19" (re-matches (re-pattern exercism.date-parser/day) "19")))) + (is (= "19" (re-matches (re-pattern date-parser/day) "19")))) (testing "un-padded 20" - (is (= "20" (re-matches (re-pattern exercism.date-parser/day) "20")))) + (is (= "20" (re-matches (re-pattern date-parser/day) "20")))) (testing "un-padded 21" - (is (= "21" (re-matches (re-pattern exercism.date-parser/day) "21")))) + (is (= "21" (re-matches (re-pattern date-parser/day) "21")))) (testing "un-padded 22" - (is (= "22" (re-matches (re-pattern exercism.date-parser/day) "22")))) + (is (= "22" (re-matches (re-pattern date-parser/day) "22")))) (testing "un-padded 23" - (is (= "23" (re-matches (re-pattern exercism.date-parser/day) "23")))) + (is (= "23" (re-matches (re-pattern date-parser/day) "23")))) (testing "un-padded 24" - (is (= "24" (re-matches (re-pattern exercism.date-parser/day) "24")))) + (is (= "24" (re-matches (re-pattern date-parser/day) "24")))) (testing "un-padded 25" - (is (= "25" (re-matches (re-pattern exercism.date-parser/day) "25")))) + (is (= "25" (re-matches (re-pattern date-parser/day) "25")))) (testing "un-padded 26" - (is (= "26" (re-matches (re-pattern exercism.date-parser/day) "26")))) + (is (= "26" (re-matches (re-pattern date-parser/day) "26")))) (testing "un-padded 27" - (is (= "27" (re-matches (re-pattern exercism.date-parser/day) "27")))) + (is (= "27" (re-matches (re-pattern date-parser/day) "27")))) (testing "un-padded 28" - (is (= "28" (re-matches (re-pattern exercism.date-parser/day) "28")))) + (is (= "28" (re-matches (re-pattern date-parser/day) "28")))) (testing "un-padded 29" - (is (= "29" (re-matches (re-pattern exercism.date-parser/day) "29")))) + (is (= "29" (re-matches (re-pattern date-parser/day) "29")))) (testing "un-padded 30" - (is (= "30" (re-matches (re-pattern exercism.date-parser/day) "30")))) + (is (= "30" (re-matches (re-pattern date-parser/day) "30")))) (testing "un-padded 31" - (is (= "31" (re-matches (re-pattern exercism.date-parser/day) "31")))) + (is (= "31" (re-matches (re-pattern date-parser/day) "31")))) (testing "un-padded 1" - (is (= "1" (re-matches (re-pattern exercism.date-parser/day) "1")))) + (is (= "1" (re-matches (re-pattern date-parser/day) "1")))) (testing "padded 02" - (is (= "02" (re-matches (re-pattern exercism.date-parser/day) "02")))) + (is (= "02" (re-matches (re-pattern date-parser/day) "02")))) (testing "padded 03" - (is (= "03" (re-matches (re-pattern exercism.date-parser/day) "03")))) + (is (= "03" (re-matches (re-pattern date-parser/day) "03")))) (testing "padded 04" - (is (= "04" (re-matches (re-pattern exercism.date-parser/day) "04")))) + (is (= "04" (re-matches (re-pattern date-parser/day) "04")))) (testing "padded 05" - (is (= "05" (re-matches (re-pattern exercism.date-parser/day) "05")))) + (is (= "05" (re-matches (re-pattern date-parser/day) "05")))) (testing "padded 06" - (is (= "06" (re-matches (re-pattern exercism.date-parser/day) "06")))) + (is (= "06" (re-matches (re-pattern date-parser/day) "06")))) (testing "padded 07" - (is (= "07" (re-matches (re-pattern exercism.date-parser/day) "07")))) + (is (= "07" (re-matches (re-pattern date-parser/day) "07")))) (testing "padded 08" - (is (= "08" (re-matches (re-pattern exercism.date-parser/day) "08")))) + (is (= "08" (re-matches (re-pattern date-parser/day) "08")))) (testing "padded 09" - (is (= "09" (re-matches (re-pattern exercism.date-parser/day) "09"))))) - (testing "numeric pattern for day doesn't match" + (is (= "09" (re-matches (re-pattern date-parser/day) "09"))))) + (testing "numeric pattern for a day that doesn't match" (testing "too few digits" - (is (nil? (re-matches (re-pattern exercism.date-parser/day) "")))) + (is (nil? (re-matches (re-pattern date-parser/day) "")))) (testing "too many digits" - (is (nil? (re-matches (re-pattern exercism.date-parser/day) "111")))) + (is (nil? (re-matches (re-pattern date-parser/day) "111")))) (testing "one letter" - (is (nil? (re-matches (re-pattern exercism.date-parser/day) "a")))) + (is (nil? (re-matches (re-pattern date-parser/day) "a")))) (testing "two letters" - (is (nil? (re-matches (re-pattern exercism.date-parser/day) "bb")))))) + (is (nil? (re-matches (re-pattern date-parser/day) "bb")))))) (deftest month-test (testing "numeric pattern for month matches" (testing "un-padded 1" - (is (= "1" (re-matches (re-pattern exercism.date-parser/month) "1")))) + (is (= "1" (re-matches (re-pattern date-parser/month) "1")))) (testing "un-padded 2" - (is (= "2" (re-matches (re-pattern exercism.date-parser/month) "2")))) + (is (= "2" (re-matches (re-pattern date-parser/month) "2")))) (testing "un-padded 3" - (is (= "3" (re-matches (re-pattern exercism.date-parser/month) "3")))) + (is (= "3" (re-matches (re-pattern date-parser/month) "3")))) (testing "un-padded 4" - (is (= "4" (re-matches (re-pattern exercism.date-parser/month) "4")))) + (is (= "4" (re-matches (re-pattern date-parser/month) "4")))) (testing "un-padded 5" - (is (= "5" (re-matches (re-pattern exercism.date-parser/month) "5")))) + (is (= "5" (re-matches (re-pattern date-parser/month) "5")))) (testing "un-padded 6" - (is (= "6" (re-matches (re-pattern exercism.date-parser/month) "6")))) + (is (= "6" (re-matches (re-pattern date-parser/month) "6")))) (testing "un-padded 7" - (is (= "7" (re-matches (re-pattern exercism.date-parser/month) "7")))) + (is (= "7" (re-matches (re-pattern date-parser/month) "7")))) (testing "un-padded 8" - (is (= "8" (re-matches (re-pattern exercism.date-parser/month) "8")))) + (is (= "8" (re-matches (re-pattern date-parser/month) "8")))) (testing "un-padded 9" - (is (= "9" (re-matches (re-pattern exercism.date-parser/month) "9")))) + (is (= "9" (re-matches (re-pattern date-parser/month) "9")))) (testing "un-padded 10" - (is (= "10" (re-matches (re-pattern exercism.date-parser/month) "10")))) + (is (= "10" (re-matches (re-pattern date-parser/month) "10")))) (testing "un-padded 11" - (is (= "11" (re-matches (re-pattern exercism.date-parser/month) "11")))) + (is (= "11" (re-matches (re-pattern date-parser/month) "11")))) (testing "un-padded 12" - (is (= "12" (re-matches (re-pattern exercism.date-parser/month) "12")))) - (testing "un-padded 1" - (is (= "1" (re-matches (re-pattern exercism.date-parser/month) "1")))) + (is (= "12" (re-matches (re-pattern date-parser/month) "12")))) + (testing "padded 01" + (is (= "01" (re-matches (re-pattern date-parser/month) "01")))) (testing "padded 02" - (is (= "02" (re-matches (re-pattern exercism.date-parser/month) "02")))) + (is (= "02" (re-matches (re-pattern date-parser/month) "02")))) (testing "padded 03" - (is (= "03" (re-matches (re-pattern exercism.date-parser/month) "03")))) + (is (= "03" (re-matches (re-pattern date-parser/month) "03")))) (testing "padded 04" - (is (= "04" (re-matches (re-pattern exercism.date-parser/month) "04")))) + (is (= "04" (re-matches (re-pattern date-parser/month) "04")))) (testing "padded 05" - (is (= "05" (re-matches (re-pattern exercism.date-parser/month) "05")))) + (is (= "05" (re-matches (re-pattern date-parser/month) "05")))) (testing "padded 06" - (is (= "06" (re-matches (re-pattern exercism.date-parser/month) "06")))) + (is (= "06" (re-matches (re-pattern date-parser/month) "06")))) (testing "padded 07" - (is (= "07" (re-matches (re-pattern exercism.date-parser/month) "07")))) + (is (= "07" (re-matches (re-pattern date-parser/month) "07")))) (testing "padded 08" - (is (= "08" (re-matches (re-pattern exercism.date-parser/month) "08")))) + (is (= "08" (re-matches (re-pattern date-parser/month) "08")))) (testing "padded 09" - (is (= "09" (re-matches (re-pattern exercism.date-parser/month) "09"))))) - (testing "numeric pattern for month doesn't match" + (is (= "09" (re-matches (re-pattern date-parser/month) "09"))))) + (testing "numeric pattern for month that doesn't match" (testing "too few digits" - (is (nil? (re-matches (re-pattern exercism.date-parser/month) "")))) + (is (nil? (re-matches (re-pattern date-parser/month) "")))) (testing "too many digits" - (is (nil? (re-matches (re-pattern exercism.date-parser/month) "111")))) + (is (nil? (re-matches (re-pattern date-parser/month) "111")))) (testing "one letter" - (is (nil? (re-matches (re-pattern exercism.date-parser/month) "a")))) + (is (nil? (re-matches (re-pattern date-parser/month) "a")))) (testing "two letters" - (is (nil? (re-matches (re-pattern exercism.date-parser/month) "bb")))) + (is (nil? (re-matches (re-pattern date-parser/month) "bb")))) (testing "short month name" - (is (nil? (re-matches (re-pattern exercism.date-parser/month) "Jan")))) + (is (nil? (re-matches (re-pattern date-parser/month) "Jan")))) (testing "long month name" - (is (nil? (re-matches (re-pattern exercism.date-parser/month) "January")))))) + (is (nil? (re-matches (re-pattern date-parser/month) "January")))))) (deftest year-test (testing "numeric pattern for year" (testing "matches 4 digits" - (is (= "1970" (re-matches (re-pattern exercism.date-parser/year) "1970")))) + (is (= "1970" (re-matches (re-pattern date-parser/year) "1970")))) (testing "doesn't match short year" - (is (nil? (re-matches (re-pattern exercism.date-parser/year) "84")))) + (is (nil? (re-matches (re-pattern date-parser/year) "84")))) (testing "doesn't match letters" - (is (nil? (re-matches (re-pattern exercism.date-parser/year) "198A")))) + (is (nil? (re-matches (re-pattern date-parser/year) "198A")))) (testing "doesn't match too few" - (is (nil? (re-matches (re-pattern exercism.date-parser/year) "198")))) + (is (nil? (re-matches (re-pattern date-parser/year) "198")))) (testing "doesn't match too many" - (is (nil? (re-matches (re-pattern exercism.date-parser/year) "19701")))))) + (is (nil? (re-matches (re-pattern date-parser/year) "19701")))))) (deftest day-names-test (testing "day names match" - (is (= "Sunday" (exercism.date-parser/day-names "Sunday"))) - (is (= "Monday" (exercism.date-parser/day-names "Monday"))) - (is (= "Tuesday" (exercism.date-parser/day-names "Tuesday"))) - (is (= "Wednesday" (exercism.date-parser/day-names "Wednesday"))) - (is (= "Thursday" (exercism.date-parser/day-names "Thursday"))) - (is (= "Friday" (exercism.date-parser/day-names "Friday"))) - (is (= "Saturday" (exercism.date-parser/day-names "Saturday")))) + (is (= "Sunday" (date-parser/day-names "Sunday"))) + (is (= "Monday" (date-parser/day-names "Monday"))) + (is (= "Tuesday" (date-parser/day-names "Tuesday"))) + (is (= "Wednesday" (date-parser/day-names "Wednesday"))) + (is (= "Thursday" (date-parser/day-names "Thursday"))) + (is (= "Friday" (date-parser/day-names "Friday"))) + (is (= "Saturday" (date-parser/day-names "Saturday")))) (testing "day names don't match" (testing "combined" - (is (nil? (exercism.date-parser/day-names "SundayMonday")))) + (is (nil? (date-parser/day-names "SundayMonday")))) (testing "short name" - (is (nil? (exercism.date-parser/day-names "Sun")))) + (is (nil? (date-parser/day-names "Sun")))) (testing "numeric day of the week (0-indexed)" - (is (nil? (exercism.date-parser/day-names "0")))) + (is (nil? (date-parser/day-names "0")))) (testing "numeric day of the week (1-indexed)" - (is (nil? (exercism.date-parser/day-names "1")))))) + (is (nil? (date-parser/day-names "1"))))) + (testing "day names don't match with trailing or leading whitespace" + (is (nil? (date-parser/day-names " Sunday "))))) (deftest month-names-test (testing "month names match" - (is (= "January" (exercism.date-parser/month-names "January"))) - (is (= "February" (exercism.date-parser/month-names "February"))) - (is (= "March" (exercism.date-parser/month-names "March"))) - (is (= "April" (exercism.date-parser/month-names "April"))) - (is (= "May" (exercism.date-parser/month-names "May"))) - (is (= "June" (exercism.date-parser/month-names "June"))) - (is (= "July" (exercism.date-parser/month-names "July"))) - (is (= "August" (exercism.date-parser/month-names "August"))) - (is (= "September" (exercism.date-parser/month-names "September"))) - (is (= "October" (exercism.date-parser/month-names "October"))) - (is (= "November" (exercism.date-parser/month-names "November"))) - (is (= "December" (exercism.date-parser/month-names "December")))) + (is (= "January" (date-parser/month-names "January"))) + (is (= "February" (date-parser/month-names "February"))) + (is (= "March" (date-parser/month-names "March"))) + (is (= "April" (date-parser/month-names "April"))) + (is (= "May" (date-parser/month-names "May"))) + (is (= "June" (date-parser/month-names "June"))) + (is (= "July" (date-parser/month-names "July"))) + (is (= "August" (date-parser/month-names "August"))) + (is (= "September" (date-parser/month-names "September"))) + (is (= "October" (date-parser/month-names "October"))) + (is (= "November" (date-parser/month-names "November"))) + (is (= "December" (date-parser/month-names "December")))) (testing "month names don't match" (testing "combined" - (is (nil? (exercism.date-parser/month-names "JanuaryFebruary")))) + (is (nil? (date-parser/month-names "JanuaryFebruary")))) (testing "short name" - (is (nil? (exercism.date-parser/month-names "Jan")))) + (is (nil? (date-parser/month-names "Jan")))) (testing "numeric month of the year (0-indexed)" - (is (nil? (exercism.date-parser/month-names "0")))) + (is (nil? (date-parser/month-names "0")))) (testing "numeric month of the year (1-indexed)" - (is (nil? (exercism.date-parser/month-names "1")))))) + (is (nil? (date-parser/month-names "1"))))) + (testing "month names don't match with trailing or leading whitespace" + (is (nil? (date-parser/day-names " January "))))) (deftest capture-test (testing "capture numeric month" - (is (= {:month "01"} (exercism.date-parser/capture-month "01")))) + (is (= {:month "01"} (date-parser/capture-month "01")))) (testing "capture numeric day" - (is (= {:day "01"} (exercism.date-parser/capture-day "01")))) + (is (= {:day "01"} (date-parser/capture-day "01")))) (testing "capture numeric year" - (is (= {:year "1970"} (exercism.date-parser/capture-year "1970")))) + (is (= {:year "1970"} (date-parser/capture-year "1970")))) (testing "capture day name" - (is (= {:day-name "Monday"} (exercism.date-parser/capture-day-name "Monday")))) + (is (= {:day-name "Monday"} (date-parser/capture-day-name "Monday")))) (testing "capture month name" - (is (= {:month-name "February"} (exercism.date-parser/capture-month-name "February")))) + (is (= {:month-name "February"} (date-parser/capture-month-name "February")))) (testing "numeric date" - (is (= {:year "1970", :month "02", :day "01"} (exercism.date-parser/capture-numeric-date "01/02/1970")))) + (is (= {:year "1970", :month "02", :day "01"} (date-parser/capture-numeric-date "01/02/1970")))) (testing "month named date" - (is (= {:year "1970", :month-name "January", :day "1"} (exercism.date-parser/capture-month-name-date "January 1, 1970")))) + (is (= {:year "1970", :month-name "January", :day "1"} (date-parser/capture-month-name-date "January 1, 1970")))) (testing "day and month named date" (is (= {:year "1970", :month-name "January", :day "1", :day-name "Thursday"} - (exercism.date-parser/capture-day-month-name-date "Thursday, January 1, 1970"))))) + (date-parser/capture-day-month-name-date "Thursday, January 1, 1970"))))) + +(deftest match-numeric-date-test + (testing "pattern to match numeric date is a regex" + (is (= java.util.regex.Pattern (type date-parser/match-numeric-date)))) + (testing "numeric date matches" + (is (= "01/02/1970" + (first (re-matches date-parser/match-numeric-date "01/02/1970"))))) + (testing "numeric date has named captures" + (is (= ["01/02/1970" "01" "02" "1970"] + (re-matches date-parser/match-numeric-date "01/02/1970")))) + (testing "numeric date with a prefix doesn't match" + (is (nil? (re-matches date-parser/match-numeric-date "The day was 01/02/1970")))) + (testing "numeric date with a suffix doesn't match" + (is (nil? (re-matches date-parser/match-numeric-date "01/02/1970 was the day")))) + (testing "pattern to match month name date is a regex" + (is (= java.util.regex.Pattern (type date-parser/match-month-name-date)))) + (testing "month named date matches" + (is (= "January 1, 1970" + (first (re-matches date-parser/match-month-name-date "January 1, 1970"))))) + (testing "month named date has named captures" + (is (= ["January 1, 1970" "January" "1" "1970"] + (re-matches date-parser/match-month-name-date "January 1, 1970")))) + (testing "month named date with a prefix doesn't match" + (is (nil? (re-matches date-parser/match-month-name-date "The day was January 1, 1970")))) + (testing "month named date with a suffix doesn't match" + (is (nil? (re-matches date-parser/match-month-name-date "January 1, 1970 was the day")))) + (testing "day and month names date matches" + (is (= "Thursday, January 1, 1970" + (first (re-matches date-parser/match-day-month-name-date "Thursday, January 1, 1970"))))) + (testing "month named date has named captures" + (is (= ["Thursday, January 1, 1970" "Thursday" "January" "1" "1970"] + (re-matches date-parser/match-day-month-name-date "Thursday, January 1, 1970")))) + (testing "day and month names date with a prefix doesn't match" + (is (nil? (re-matches date-parser/match-day-month-name-date "The day way Thursday, January 1, 1970")))) + (testing "day and month names date with a suffix doesn't match" + (is (nil? (re-matches date-parser/match-day-month-name-date "Thursday, January 1, 1970 was the day"))))) + + +(clojure.test/run-tests) \ No newline at end of file From ecd23de0b4b7e57fe10e77b31275a27169bc2798 Mon Sep 17 00:00:00 2001 From: Bobby Towers Date: Tue, 7 Jun 2022 16:30:40 -0700 Subject: [PATCH 2/4] create exercise stub --- .../concept/date-parser/src/date_parser.clj | 74 ++++--------------- 1 file changed, 15 insertions(+), 59 deletions(-) diff --git a/exercises/concept/date-parser/src/date_parser.clj b/exercises/concept/date-parser/src/date_parser.clj index e7d5d3ba0..050f842a4 100644 --- a/exercises/concept/date-parser/src/date_parser.clj +++ b/exercises/concept/date-parser/src/date_parser.clj @@ -1,73 +1,29 @@ (ns date-parser) -(def day "\\d{1,2}") -(def month "\\d{1,2}") -(def year "\\d{4}") +(def day) +(def month) +(def year) -(re-matches #"\d{1,}" "0") +(def days) -(def days "Sunday|Monday|Tuesday|Wednesday|Thursday|Friday|Saturday") +(defn day-names [s]) -(defn day-names [s] - (re-matches (re-pattern days) s)) +(def months) -(def months "January|February|March|April|May|June|July|August|September|October|November|December") +(defn month-names [s]) -(defn month-names [s] - (re-matches (re-pattern months) s)) +(defn capture-month [s]) -(defn capture-month [s] - (let [matcher (re-matcher (re-pattern (str "(?" month ")")) s)] - (when (.matches matcher) - {:month (.group matcher "month")}))) +(defn capture-day [s]) -(def anchor "$") -(def regex (re-pattern (str "end of the line" anchor))) -(re-matches regex "end of the line") +(defn capture-year [s]) -(defn capture-day [s] - (let [matcher (re-matcher (re-pattern (str "(?" day ")")) s)] - (when (.matches matcher) - {:day (.group matcher "day")}))) +(defn capture-month-name [s]) -(defn capture-year [s] - (let [matcher (re-matcher (re-pattern (str "(?" year ")")) s)] - (when (.matches matcher) - {:year (.group matcher "year")}))) +(defn capture-day-name [s]) -(defn capture-month-name [s] - {:month-name (first (re-find (re-pattern (str "(?" months ")")) s))}) +(defn capture-numeric-date [s]) -(defn capture-day-name [s] - {:day-name (first (re-find (re-pattern (str "(?" days ")")) s))}) +(defn capture-month-name-date [s]) -(defn capture-numeric-date [s] - (let [matcher (re-matcher (re-pattern (str "(?" day ")/(?" month ")/(?" year ")")) s)] - (when (.matches matcher) - {:day (.group matcher "day") - :month (.group matcher "month") - :year (.group matcher "year")}))) - -(defn capture-month-name-date [s] - (let [matcher (re-matcher (re-pattern (str "(?" months ") (?" day "), (?" year ")")) s)] - (when (.matches matcher) - {:month-name (.group matcher "month") - :day (.group matcher "day") - :year (.group matcher "year")}))) - -(defn capture-day-month-name-date [s] - (let [matcher (re-matcher (re-pattern (str "(?" days "), (?" months ") (?" day "), (?" year ")")) s)] - (when (.matches matcher) - {:day-name (.group matcher "dayname") - :month-name (.group matcher "month") - :day (.group matcher "day") - :year (.group matcher "year")}))) - -(def match-numeric-date - (re-pattern (str "(?" day ")/(?" month ")/(?" year ")"))) - -(def match-month-name-date - (re-pattern (str "(?" months ") (?" day "), (?" year ")"))) - -(def match-day-month-name-date - (re-pattern (str "(?" days "), (?" months ") (?" day "), (?" year ")"))) +(defn capture-day-month-name-date [s]) From fa29082c167b0a26c328f2c94762e885e2d0ba0b Mon Sep 17 00:00:00 2001 From: Bobby Towers Date: Tue, 7 Jun 2022 16:32:19 -0700 Subject: [PATCH 3/4] add task 5 functions --- exercises/concept/date-parser/.meta/exemplar.clj | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/exercises/concept/date-parser/.meta/exemplar.clj b/exercises/concept/date-parser/.meta/exemplar.clj index 689bdfe13..cfd30a645 100644 --- a/exercises/concept/date-parser/.meta/exemplar.clj +++ b/exercises/concept/date-parser/.meta/exemplar.clj @@ -56,3 +56,12 @@ :month-name (.group matcher "month") :day (.group matcher "day") :year (.group matcher "year")}))) + +(def match-numeric-date + (re-pattern (str "(?" day ")/(?" month ")/(?" year ")"))) + +(def match-month-name-date + (re-pattern (str "(?" months ") (?" day "), (?" year ")"))) + +(def match-day-month-name-date + (re-pattern (str "(?" days "), (?" months ") (?" day "), (?" year ")"))) \ No newline at end of file From e9641d49952a983f85a1caf01676e8d9203d0a0f Mon Sep 17 00:00:00 2001 From: Bobby Towers Date: Tue, 7 Jun 2022 16:33:54 -0700 Subject: [PATCH 4/4] clean up test file --- exercises/concept/date-parser/test/date_parser_test.clj | 3 --- 1 file changed, 3 deletions(-) diff --git a/exercises/concept/date-parser/test/date_parser_test.clj b/exercises/concept/date-parser/test/date_parser_test.clj index 2a9f25cb9..2dd99dde8 100644 --- a/exercises/concept/date-parser/test/date_parser_test.clj +++ b/exercises/concept/date-parser/test/date_parser_test.clj @@ -266,6 +266,3 @@ (is (nil? (re-matches date-parser/match-day-month-name-date "The day way Thursday, January 1, 1970")))) (testing "day and month names date with a suffix doesn't match" (is (nil? (re-matches date-parser/match-day-month-name-date "Thursday, January 1, 1970 was the day"))))) - - -(clojure.test/run-tests) \ No newline at end of file