From 71e2f7ffa7ff3cee6cba5ce87deb51fed90ee100 Mon Sep 17 00:00:00 2001 From: Kah Goh Date: Sat, 24 Feb 2024 01:55:59 +0800 Subject: [PATCH] Sync Word Count with problem specifications (#201) --- .../practice/word-count/.meta/example.lfe | 32 ++++--- .../word-count/src/word-count.app.src | 3 +- .../practice/word-count/src/word-count.lfe | 4 + .../word-count/test/word-count-tests.lfe | 83 ++++++++++++++++++- 4 files changed, 108 insertions(+), 14 deletions(-) diff --git a/exercises/practice/word-count/.meta/example.lfe b/exercises/practice/word-count/.meta/example.lfe index 87097148..7407b280 100644 --- a/exercises/practice/word-count/.meta/example.lfe +++ b/exercises/practice/word-count/.meta/example.lfe @@ -3,18 +3,30 @@ (defun count (string) (lists:foldl - (lambda (k acc) - (dict:update_counter k 1 acc)) + (lambda (word acc) + (dict:update_counter word 1 acc)) (dict:new) (tokenize (string:to_lower string)))) -(defun alnum? (char) (orelse (=< #\a char #\z) (=< #\0 char #\9))) +(defun unquote + (((cons #\' remaining)) + (case (lists:last remaining) + (#\' (lists:sublist remaining 1 (- (length remaining) 1))) + (_ (cons #\' remaining)))) + ((word) word)) -(defun sep? (char) (not (alnum? char))) +(defun tokenize-loop + ; End of sentence with no more words + (('() '() acc) acc) + ; End of sentence with one more word + (('() word-acc acc) (cons (unquote (lists:reverse word-acc)) acc)) + ; Lower case character, number or apostrophe + (((cons char remaining) word-acc acc) + (when (or (and (>= char #\a) (=< char #\z)) (and (>= char #\0) (=< char #\9)) (== char #\'))) + (tokenize-loop remaining (cons char word-acc) acc)) + ; Boundary or junk with no word in word accumulator (skip it) + (((cons _ remaining) '() acc) (tokenize-loop remaining '() acc)) + ; Boundary or junk with something in word accumulator (add the word to the accumulator) + (((cons _ remaining) word-acc acc) (tokenize-loop remaining '() (cons (unquote (lists:reverse word-acc)) acc)))) -(defun tokenize - ([()] ()) - ([string] - (case (lists:splitwith #'alnum?/1 (lists:dropwhile #'sep?/1 string)) - (`#([] ,rest) (tokenize rest)) - (`#(,word ,rest) (cons word (tokenize rest)))))) +(defun tokenize (text) (tokenize-loop text '() '())) diff --git a/exercises/practice/word-count/src/word-count.app.src b/exercises/practice/word-count/src/word-count.app.src index 22df9dbb..a3ab31f2 100644 --- a/exercises/practice/word-count/src/word-count.app.src +++ b/exercises/practice/word-count/src/word-count.app.src @@ -1,6 +1,7 @@ %% -*- erlang -*- {application, 'word-count', - [{description, ""}, + [{description, "Given a phrase, count the occurrences of each word in that phrase." +}, {vsn, "0.0.1"}, {modules, ['word-count']}, diff --git a/exercises/practice/word-count/src/word-count.lfe b/exercises/practice/word-count/src/word-count.lfe index e69de29b..5fbb4b04 100644 --- a/exercises/practice/word-count/src/word-count.lfe +++ b/exercises/practice/word-count/src/word-count.lfe @@ -0,0 +1,4 @@ +(defmodule word-count + (export (count 1))) + +; Please implement the `count` function \ No newline at end of file diff --git a/exercises/practice/word-count/test/word-count-tests.lfe b/exercises/practice/word-count/test/word-count-tests.lfe index d3161ea5..fd0f9c60 100644 --- a/exercises/practice/word-count/test/word-count-tests.lfe +++ b/exercises/practice/word-count/test/word-count-tests.lfe @@ -27,9 +27,23 @@ #("red" 1) #("blue" 1)))) +(deftest handles-cramped-lists + (assert-count + "one,two,three" + '(#("one" 1) + #("two" 1) + #("three" 1)))) + +(deftest handles-expanded-lists + (assert-count + "one,\ntwo,\nthree" + '(#("one" 1) + #("two" 1) + #("three" 1)))) + (deftest ignore-punctuation (assert-count - "car : carpet as java : javascript!!&@$%^&" + "car: carpet as java: javascript!!&@$%^&" '(#("car" 1) #("carpet" 1) #("as" 1) @@ -45,8 +59,71 @@ (deftest normalize-case (assert-count - "go Go GO" - '(#("go" 3)))) + "go Go GO Stop stop" + '(#("go" 3) + #("stop" 2)))) + +(deftest with-apostrophes + (assert-count + "First: don't laugh. Then: don't cry." + '(#("first" 1) + #("don't" 2) + #("laugh" 1) + #("then" 1) + #("cry" 1)))) + +(deftest with-apostrophes-multiple-letters + (assert-count + "First don't laugh. then: don't cry. You're getting it." + '(#("first" 1) + #("don't" 2) + #("laugh" 1) + #("then" 1) + #("cry" 1) + #("you're" 1) + #("getting" 1) + #("it" 1)))) + +(deftest with-quotations + (assert-count + "Joe can't tell between 'large' and large." + '(#("joe" 1) + #("can't" 1) + #("tell" 1) + #("between" 1) + #("large" 2) + #("and" 1)))) + +(deftest substrings-from-the-beginning + (assert-count + "Joe can't tell between app, apple and a." + '(#("joe" 1) + #("can't" 1) + #("tell" 1) + #("between" 1) + #("app" 1) + #("apple" 1) + #("and" 1) + #("a" 1)))) + +(deftest multiple-spaces-not-detected-as-a-word + (assert-count + " multiple whitespaces" + '(#("multiple" 1) + #("whitespaces" 1)))) + +(deftest alternating-word-separators-not-detected-as-a-word + (assert-count + ",\n,one,\n ,two \n 'three'" + '(#("one" 1) + #("two" 1) + #("three" 1)))) + +(deftest quotation-for-word-with-apostrophe + (assert-count + "can, can't, 'can't'" + '(#("can" 1) + #("can't" 2)))) (deftest prefix-punctuation (assert-count