diff --git a/config.json b/config.json index abc5adb0..a14f10f6 100644 --- a/config.json +++ b/config.json @@ -182,6 +182,16 @@ "prerequisites": [], "difficulty": 5 }, + { + "slug": "word-count", + "name": "Word Count", + "uuid": "a8f558ad-28df-46fa-9ac7-aac9afad5a67", + "practices": [], + "prerequisites": [], + "difficulty": 1, + "topics": ["loops", "lists", "regular_expressions", "strings"], + "status": "wip" + }, { "slug": "beer-song", "name": "Beer Song", diff --git a/exercises/practice/word-count/.docs/instructions.md b/exercises/practice/word-count/.docs/instructions.md new file mode 100644 index 00000000..ea8028e2 --- /dev/null +++ b/exercises/practice/word-count/.docs/instructions.md @@ -0,0 +1,31 @@ +# Instructions + +Given a phrase, count the occurrences of each _word_ in that phrase. + +For the purposes of this exercise you can expect that a _word_ will always be one of: + +1. A _number_ composed of one or more ASCII digits (ie "0" or "1234") OR +2. A _simple word_ composed of one or more ASCII letters (ie "a" or "they") OR +3. A _contraction_ of two _simple words_ joined by a single apostrophe (ie "it's" is "its" ) + +When counting words you can assume the following rules: + +1. The count is _case insensitive_ (ie "You", "you", and "YOU" are 3 uses of the same word) +2. The count is _unordered_; the tests will ignore how words and counts are ordered +3. Other than the apostrophe in a _contraction_ all forms of _punctuation_ are ignored +4. The words can be separated by _any_ form of whitespace (ie "\t", "\n", " ") + +For example, for the phrase `"That's the password: 'PASSWORD 123'!", cried the Special Agent.\nSo I fled.` the count would be: + +```text +thats: 1 +the: 2 +password: 2 +123: 1 +cried: 1 +special: 1 +agent: 1 +so: 1 +i: 1 +fled: 1 +``` diff --git a/exercises/practice/word-count/.meta/config.json b/exercises/practice/word-count/.meta/config.json new file mode 100644 index 00000000..f0b2fb29 --- /dev/null +++ b/exercises/practice/word-count/.meta/config.json @@ -0,0 +1,20 @@ +{ + "authors": [ + "marianfoo" + ], + "contributors": [], + "files": { + "solution": [ + "zcl_word_count.clas.abap" + ], + "test": [ + "zcl_word_count.clas.testclasses.abap" + ], + "example": [ + ".meta/zcl_word_count.clas.abap" + ] + }, + "blurb": "Given a phrase, count the occurrences of each word in that phrase.", + "source": "This is a classic toy problem, but we were reminded of it by seeing it in the Go Tour.", + "source_url": "https://github.com/exercism/javascript/tree/main/exercises/practice/word-count" + } \ No newline at end of file diff --git a/exercises/practice/word-count/.meta/zcl_word_count.clas.abap b/exercises/practice/word-count/.meta/zcl_word_count.clas.abap new file mode 100644 index 00000000..3e29fc27 --- /dev/null +++ b/exercises/practice/word-count/.meta/zcl_word_count.clas.abap @@ -0,0 +1,55 @@ +CLASS zcl_word_count DEFINITION + PUBLIC + FINAL + CREATE PUBLIC . + + PUBLIC SECTION. + TYPES: + BEGIN OF return_structure, + word TYPE string, + count TYPE i, + END OF return_structure, + return_table TYPE STANDARD TABLE OF return_structure WITH KEY word. + METHODS count_words + IMPORTING + !phrase TYPE string + RETURNING + VALUE(result) TYPE return_table . + PROTECTED SECTION. + PRIVATE SECTION. +ENDCLASS. + + +CLASS zcl_word_count IMPLEMENTATION. + + METHOD count_words. + DATA(clean) = replace( val = to_lower( phrase ) + sub = `'` + with = `` + occ = 0 ). + clean = replace( val = clean + sub = `\n` + with = ` ` + occ = 0 ). + clean = replace( val = clean + sub = `\t` + with = ` ` + occ = 0 ). + clean = replace( val = clean + regex = `[^a-z0-9]` + with = ` ` + occ = 0 ). + + SPLIT condense( clean ) AT ` ` INTO TABLE DATA(words). + + LOOP AT words ASSIGNING FIELD-SYMBOL(). + DATA(one_result) = VALUE return_structure( word = count = 1 ). + READ TABLE result ASSIGNING FIELD-SYMBOL() WITH TABLE KEY word = one_result-word. + IF sy-subrc = 0. + -count = -count + one_result-count. + ELSE. + INSERT one_result INTO TABLE result. + ENDIF. + ENDLOOP. + ENDMETHOD. +ENDCLASS. \ No newline at end of file diff --git a/exercises/practice/word-count/package.devc.xml b/exercises/practice/word-count/package.devc.xml new file mode 100644 index 00000000..0bd2ccda --- /dev/null +++ b/exercises/practice/word-count/package.devc.xml @@ -0,0 +1,10 @@ + + + + + + Exercism: Word Count + + + + diff --git a/exercises/practice/word-count/zcl_word_count.clas.abap b/exercises/practice/word-count/zcl_word_count.clas.abap new file mode 100644 index 00000000..0e1a31d2 --- /dev/null +++ b/exercises/practice/word-count/zcl_word_count.clas.abap @@ -0,0 +1,28 @@ +CLASS zcl_word_count DEFINITION + PUBLIC + FINAL + CREATE PUBLIC . + + PUBLIC SECTION. + TYPES: + BEGIN OF return_structure, + word TYPE string, + count TYPE i, + END OF return_structure, + return_table TYPE STANDARD TABLE OF return_structure WITH KEY word. + METHODS count_words + IMPORTING + !phrase TYPE string + RETURNING + VALUE(result) TYPE return_table . + PROTECTED SECTION. + PRIVATE SECTION. +ENDCLASS. + + +CLASS zcl_word_count IMPLEMENTATION. + + METHOD count_words. + "Add solution here + ENDMETHOD. +ENDCLASS. diff --git a/exercises/practice/word-count/zcl_word_count.clas.testclasses.abap b/exercises/practice/word-count/zcl_word_count.clas.testclasses.abap new file mode 100644 index 00000000..20435478 --- /dev/null +++ b/exercises/practice/word-count/zcl_word_count.clas.testclasses.abap @@ -0,0 +1,224 @@ +CLASS ltcl_word_count DEFINITION FOR TESTING RISK LEVEL HARMLESS DURATION SHORT FINAL. + + PRIVATE SECTION. + + DATA cut TYPE REF TO zcl_word_count. + METHODS setup. + METHODS test_one_word FOR TESTING RAISING cx_static_check. + METHODS test_three_words FOR TESTING RAISING cx_static_check. + METHODS test_five_words_multiple FOR TESTING RAISING cx_static_check. + METHODS test_three_words_comma FOR TESTING RAISING cx_static_check. + METHODS test_three_words_linebreak FOR TESTING RAISING cx_static_check. + METHODS test_special_character FOR TESTING RAISING cx_static_check. + METHODS test_words_number_comma FOR TESTING RAISING cx_static_check. + METHODS test_case_insensitive FOR TESTING RAISING cx_static_check. + METHODS test_colon_apostrophe FOR TESTING RAISING cx_static_check. + METHODS test_apostrophe FOR TESTING RAISING cx_static_check. + METHODS test_comma_apostroph FOR TESTING RAISING cx_static_check. + METHODS test_whitespaces FOR TESTING RAISING cx_static_check. + METHODS test_comma_linebreaks FOR TESTING RAISING cx_static_check. + + +ENDCLASS. + +CLASS ltcl_word_count IMPLEMENTATION. + + METHOD setup. + cut = NEW zcl_word_count( ). + ENDMETHOD. + + + METHOD test_one_word. + DATA(exp) = VALUE zcl_word_count=>return_table( + ( word = 'word' count = 1 ) ). + DATA(act) = cut->count_words( 'word' ). + + SORT exp BY word. + SORT act BY word. + cl_abap_unit_assert=>assert_equals( + act = act + exp = exp ). + ENDMETHOD. + + METHOD test_three_words. + DATA(exp) = VALUE zcl_word_count=>return_table( + ( word = 'one' count = 1 ) + ( word = 'of' count = 1 ) + ( word = 'each' count = 1 ) ). + DATA(act) = cut->count_words( 'one of each' ). + + SORT exp BY word. + SORT act BY word. + cl_abap_unit_assert=>assert_equals( + act = act + exp = exp ). + ENDMETHOD. + + METHOD test_five_words_multiple. + DATA(exp) = VALUE zcl_word_count=>return_table( + ( word = 'one' count = 1 ) + ( word = 'fish' count = 4 ) + ( word = 'two' count = 1 ) + ( word = 'red' count = 1 ) + ( word = 'blue' count = 1 ) ). + DATA(act) = cut->count_words( 'one fish two fish red fish blue fish' ). + + SORT exp BY word. + SORT act BY word. + cl_abap_unit_assert=>assert_equals( + act = act + exp = exp ). + ENDMETHOD. + + METHOD test_three_words_comma. + DATA(exp) = VALUE zcl_word_count=>return_table( + ( word = 'one' count = 1 ) + ( word = 'three' count = 1 ) + ( word = 'two' count = 1 ) ). + DATA(act) = cut->count_words( 'one,two,three' ). + + SORT exp BY word. + SORT act BY word. + cl_abap_unit_assert=>assert_equals( + act = act + exp = exp ). + ENDMETHOD. + + METHOD test_three_words_linebreak. + DATA(exp) = VALUE zcl_word_count=>return_table( + ( word = 'one' count = 1 ) + ( word = 'three' count = 1 ) + ( word = 'two' count = 1 ) ). + DATA(act) = cut->count_words( 'one,\ntwo,\nthree' ). + + SORT exp BY word. + SORT act BY word. + cl_abap_unit_assert=>assert_equals( + act = act + exp = exp ). + ENDMETHOD. + + METHOD test_special_character. + DATA(exp) = VALUE zcl_word_count=>return_table( + ( word = 'car' count = 1 ) + ( word = 'carpet' count = 1 ) + ( word = 'as' count = 1 ) + ( word = 'java' count = 1 ) + ( word = 'javascript' count = 1 ) ). + DATA(act) = cut->count_words( 'car: carpet as java: javascript!!&@$%^&' ). + + SORT exp BY word. + SORT act BY word. + cl_abap_unit_assert=>assert_equals( + act = act + exp = exp ). + ENDMETHOD. + + METHOD test_words_number_comma. + DATA(exp) = VALUE zcl_word_count=>return_table( + ( word = 'testing' count = 2 ) + ( word = '1' count = 1 ) + ( word = '2' count = 1 ) ). + DATA(act) = cut->count_words( 'testing, 1, 2 testing' ). + + SORT exp BY word. + SORT act BY word. + cl_abap_unit_assert=>assert_equals( + act = act + exp = exp ). + ENDMETHOD. + + METHOD test_case_insensitive. + DATA(exp) = VALUE zcl_word_count=>return_table( + ( word = 'go' count = 3 ) + ( word = 'stop' count = 2 ) ). + DATA(act) = cut->count_words( 'go Go GO Stop stop' ). + + SORT exp BY word. + SORT act BY word. + cl_abap_unit_assert=>assert_equals( + act = act + exp = exp ). + ENDMETHOD. + + METHOD test_colon_apostrophe. + DATA(exp) = VALUE zcl_word_count=>return_table( + ( word = 'first' count = 1 ) + ( word = 'dont' count = 2 ) + ( word = 'laugh' count = 1 ) + ( word = 'then' count = 1 ) + ( word = 'cry' count = 1 ) ). + DATA(act) = cut->count_words( `First: don't laugh. Then: don't cry.` ). + + SORT exp BY word. + SORT act BY word. + cl_abap_unit_assert=>assert_equals( + act = act + exp = exp ). + ENDMETHOD. + + METHOD test_apostrophe. + DATA(exp) = VALUE zcl_word_count=>return_table( + ( word = 'joe' count = 1 ) + ( word = 'cant' count = 1 ) + ( word = 'tell' count = 1 ) + ( word = 'between' count = 1 ) + ( word = 'large' count = 2 ) + ( word = 'and' count = 1 ) ). + DATA(act) = cut->count_words( `Joe can't tell between 'large' and large.` ). + + SORT exp BY word. + SORT act BY word. + cl_abap_unit_assert=>assert_equals( + act = act + exp = exp ). + ENDMETHOD. + + METHOD test_comma_apostroph. + DATA(exp) = VALUE zcl_word_count=>return_table( + ( word = 'joe' count = 1 ) + ( word = 'cant' count = 1 ) + ( word = 'tell' count = 1 ) + ( word = 'between' count = 1 ) + ( word = 'app' count = 1 ) + ( word = 'apple' count = 1 ) + ( word = 'and' count = 1 ) + ( word = 'a' count = 1 ) ). + DATA(act) = cut->count_words( `Joe can't tell between app, apple and a.'` ). + + SORT exp BY word. + SORT act BY word. + cl_abap_unit_assert=>assert_equals( + act = act + exp = exp ). + ENDMETHOD. + + METHOD test_whitespaces. + DATA(exp) = VALUE zcl_word_count=>return_table( + ( word = 'multiple' count = 1 ) + ( word = 'whitespaces' count = 1 ) ). + DATA(act) = cut->count_words( ` multiple whitespaces` ). + + SORT exp BY word. + SORT act BY word. + cl_abap_unit_assert=>assert_equals( + act = act + exp = exp ). + ENDMETHOD. + + METHOD test_comma_linebreaks. + DATA(exp) = VALUE zcl_word_count=>return_table( + ( word = 'one' count = 1 ) + ( word = 'three' count = 1 ) + ( word = 'two' count = 1 ) ). + DATA(act) = cut->count_words( `,\n,one,\n ,two \n 'three'` ). + + SORT exp BY word. + SORT act BY word. + cl_abap_unit_assert=>assert_equals( + act = act + exp = exp ). + ENDMETHOD. + + +ENDCLASS. diff --git a/exercises/practice/word-count/zcl_word_count.clas.xml b/exercises/practice/word-count/zcl_word_count.clas.xml new file mode 100644 index 00000000..5819a9af --- /dev/null +++ b/exercises/practice/word-count/zcl_word_count.clas.xml @@ -0,0 +1,17 @@ + + + + + + ZCL_WORD_COUNT + E + Exercism: Word Count + 1 + X + X + X + X + + + +