Word count

This commit is contained in:
2023-07-25 22:24:57 +02:00
parent 1ccf7cb4fa
commit 619044ad23
18 changed files with 29748 additions and 0 deletions
+13
View File
@@ -0,0 +1,13 @@
!.meta
# Protected or generated
.git
.vscode
# When using npm
node_modules/*
# Configuration files
.eslintrc.cjs
babel.config.cjs
jest.config.cjs
+38
View File
@@ -0,0 +1,38 @@
module.exports = {
root: true,
parserOptions: {
tsconfigRootDir: __dirname,
project: ['./tsconfig.json'],
},
overrides: [
// Student provided files
{
files: ['*.ts'],
excludedFiles: ['.meta/proof.ci.ts', '.meta/exemplar.ts', '*.test.ts'],
extends: '@exercism/eslint-config-typescript',
},
// Exercism given tests
{
files: ['*.test.ts'],
excludedFiles: ['custom.test.ts'],
env: {
jest: true,
},
extends: '@exercism/eslint-config-typescript/maintainers',
},
// Student provided tests
{
files: ['custom.test.ts'],
env: {
jest: true,
},
extends: '@exercism/eslint-config-typescript',
},
// Exercism provided files
{
files: ['.meta/proof.ci.ts', '.meta/exemplar.ts', '*.test.ts'],
excludedFiles: ['custom.test.ts'],
extends: '@exercism/eslint-config-typescript/maintainers',
},
],
}
@@ -0,0 +1,23 @@
{
"authors": [
"masters3d"
],
"contributors": [
"lukaszklis",
"SleeplessByte",
"angelikatyborska"
],
"files": {
"solution": [
"word-count.ts"
],
"test": [
"word-count.test.ts"
],
"example": [
".meta/proof.ci.ts"
]
},
"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."
}
@@ -0,0 +1 @@
{"track":"typescript","exercise":"word-count","id":"cce122a248e44dd89a7b6f6048ff1353","url":"https://exercism.org/tracks/typescript/exercises/word-count","handle":"briemens","is_requester":true,"auto_approve":false}
+19812
View File
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large Load Diff
Binary file not shown.
File diff suppressed because one or more lines are too long
+1
View File
@@ -0,0 +1 @@
yarnPath: .yarn/releases/yarn-3.6.0.cjs
+44
View File
@@ -0,0 +1,44 @@
# Help
## Running the tests
Execute the tests with:
```bash
$ yarn test
```
## Skipped tests
In the test suites all tests but the first have been skipped.
Once you get a test passing, you can enable the next one by changing `xit` to
`it`.
## Submitting your solution
You can submit your solution using the `exercism submit word-count.ts` command.
This command will upload your solution to the Exercism website and print the solution page's URL.
It's possible to submit an incomplete solution which allows you to:
- See how others have completed the exercise
- Request help from a mentor
## Need to get help?
If you'd like help solving the exercise, check the following pages:
- The [TypeScript track's documentation](https://exercism.org/docs/tracks/typescript)
- [Exercism's programming category on the forum](https://forum.exercism.org/c/programming/5)
- The [Frequently Asked Questions](https://exercism.org/docs/using/faqs)
Should those resources not suffice, you could submit your (incomplete) solution to request mentoring.
To get help if you're having trouble, you can use one of the following resources:
- [TypeScript QuickStart](https://www.typescriptlang.org/docs/handbook/release-notes/overview.html)
- [ECMAScript 2015 Language Specification](https://www.ecma-international.org/wp-content/uploads/ECMA-262_6th_edition_june_2015.pdf) (pdf)
- [Mozilla JavaScript Reference](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference)
- [/r/typescript](https://www.reddit.com/r/typescript) is the TypeScript subreddit.
- [StackOverflow](https://stackoverflow.com/questions/tagged/typescript) can be used to search for your problem and see if it has been answered already. You can also ask and answer questions.
+77
View File
@@ -0,0 +1,77 @@
# Word Count
Welcome to Word Count on Exercism's TypeScript Track.
If you need help running the tests or submitting your code, check out `HELP.md`.
## Introduction
You teach English as a foreign language to high school students.
You've decided to base your entire curriculum on TV shows.
You need to analyze which words are used, and how often they're repeated.
This will let you choose the simplest shows to start with, and to gradually increase the difficulty as time passes.
## Instructions
Your task is to count how many times each word occurs in a subtitle of a drama.
The subtitles from these dramas use only ASCII characters.
The characters often speak in casual English, using contractions like _they're_ or _it's_.
Though these contractions come from two words (e.g. _we are_), the contraction (_we're_) is considered a single word.
Words can be separated by any form of punctuation (e.g. ":", "!", or "?") or whitespace (e.g. "\t", "\n", or " ").
The only punctuation that does not separate words is the apostrophe in contractions.
Numbers are considered words.
If the subtitles say _It costs 100 dollars._ then _100_ will be its own word.
Words are case insensitive.
For example, the word _you_ occurs three times in the following sentence:
> You come back, you hear me? DO YOU HEAR ME?
The ordering of the word counts in the results doesn't matter.
Here's an example that incorporates several of the elements discussed above:
- simple words
- contractions
- numbers
- case insensitive words
- punctuation (including apostrophes) to separate words
- different forms of whitespace to separate words
`"That's the password: 'PASSWORD 123'!", cried the Special Agent.\nSo I fled.`
The mapping for this subtitle would be:
```text
123: 1
agent: 1
cried: 1
fled: 1
i: 1
password: 2
so: 1
special: 1
that's: 1
the: 2
```
## Source
### Created by
- @masters3d
### Contributed to by
- @lukaszklis
- @SleeplessByte
- @angelikatyborska
### Based on
This is a classic toy problem, but we were reminded of it by seeing it in the Go Tour.
+4
View File
@@ -0,0 +1,4 @@
module.exports = {
presets: ['@exercism/babel-preset-typescript'],
plugins: [],
}
+19
View File
@@ -0,0 +1,19 @@
module.exports = {
verbose: true,
projects: ['<rootDir>'],
testMatch: [
'**/__tests__/**/*.[jt]s?(x)',
'**/test/**/*.[jt]s?(x)',
'**/?(*.)+(spec|test).[jt]s?(x)',
],
testPathIgnorePatterns: [
'/(?:production_)?node_modules/',
'.d.ts$',
'<rootDir>/test/fixtures',
'<rootDir>/test/helpers',
'__mocks__',
],
transform: {
'^.+\\.[jt]sx?$': 'babel-jest',
},
}
+32
View File
@@ -0,0 +1,32 @@
{
"name": "@exercism/typescript-word-count",
"version": "1.0.0",
"description": "Exercism exercises in Typescript.",
"private": true,
"repository": {
"type": "git",
"url": "https://github.com/exercism/typescript"
},
"type": "module",
"engines": {
"node": "^18.16.0 || >=20.0.0"
},
"devDependencies": {
"@exercism/babel-preset-typescript": "^0.4.0",
"@exercism/eslint-config-typescript": "^0.5.0",
"@types/jest": "^29.5.2",
"@types/node": "~18.16.16",
"babel-jest": "^29.5.0",
"core-js": "~3.30.2",
"eslint": "^8.42.0",
"jest": "^29.5.0",
"typescript": "~5.0.4"
},
"scripts": {
"test": "yarn lint:types && jest --no-cache",
"lint": "yarn lint:types && yarn lint:ci",
"lint:types": "yarn tsc --noEmit -p .",
"lint:ci": "eslint . --ext .tsx,.ts"
},
"packageManager": "yarn@3.6.0"
}
+28
View File
@@ -0,0 +1,28 @@
{
"display": "Configuration for Exercism TypeScript Exercises",
"compilerOptions": {
// Allows you to use the newest syntax, and have access to console.log
// https://www.typescriptlang.org/tsconfig#lib
"lib": ["ESNEXT", "dom"],
// Make sure typescript is configured to output ESM
// https://gist.github.com/sindresorhus/a39789f98801d908bbc7ff3ecc99d99c#how-can-i-make-my-typescript-project-output-esm
"module": "ES2020",
// Since this project is using babel, TypeScript may target something very
// high, and babel will make sure it runs on your local Node version.
// https://babeljs.io/docs/en/
"target": "ESNext", // ESLint doesn't support this yet: "es2022",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
// Because we'll be using babel: ensure that Babel can safely transpile
// files in the TypeScript project.
//
// https://babeljs.io/docs/en/babel-plugin-transform-typescript/#caveats
"isolatedModules": true
},
"include": ["*.ts", "*.tsx", ".meta/*.ts", ".meta/*.tsx"],
"exclude": ["node_modules"]
}
+127
View File
@@ -0,0 +1,127 @@
import { count } from './word-count'
describe('count()', () => {
it('counts one word', () => {
const expectedCounts = new Map(Object.entries({ word: 1 }))
expect(count('word')).toEqual(expectedCounts)
})
it('counts one of each', () => {
const expectedCounts = new Map(Object.entries({ one: 1, of: 1, each: 1 }))
expect(count('one of each')).toEqual(expectedCounts)
})
it('counts multiple occurrences', () => {
const expectedCounts = new Map(
Object.entries({ one: 1, fish: 4, two: 1, red: 1, blue: 1 })
)
expect(count('one fish two fish red fish blue fish')).toEqual(
expectedCounts
)
})
it('handles cramped lists', () => {
const expectedCounts = new Map(Object.entries({ one: 1, two: 1, three: 1 }))
expect(count('one,two,three')).toEqual(expectedCounts)
})
it('handles expanded lists', () => {
const expectedCounts = new Map(Object.entries({ one: 1, two: 1, three: 1 }))
expect(count('one,\ntwo,\nthree')).toEqual(expectedCounts)
})
it('ignores punctuation', () => {
const expectedCounts = new Map(
Object.entries({
car: 1,
carpet: 1,
as: 1,
java: 1,
javascript: 1,
})
)
expect(count('car: carpet as java: javascript!!&@$%^&"')).toEqual(
expectedCounts
)
})
it('includes numbers', () => {
const expectedCounts = new Map(Object.entries({ testing: 2, 1: 1, 2: 1 }))
expect(count('testing, 1, 2 testing')).toEqual(expectedCounts)
})
it('normalizes case', () => {
const expectedCounts = new Map(Object.entries({ go: 3, stop: 2 }))
expect(count('go Go GO Stop stop')).toEqual(expectedCounts)
})
it('with apostrophes', () => {
const expectedCounts = new Map(
Object.entries({
first: 1,
"don't": 2,
laugh: 1,
then: 1,
cry: 1,
"you're": 1,
getting: 1,
it: 1,
})
)
expect(
count("'First: don't laugh. Then: don't cry. You're getting it.'")
).toEqual(expectedCounts)
})
it('substrings from the beginning', () => {
const expectedCounts = new Map(
Object.entries({
joe: 1,
"can't": 1,
tell: 1,
between: 1,
app: 1,
apple: 1,
and: 1,
a: 1,
})
)
expect(count("Joe can't tell between app, apple and a.")).toEqual(
expectedCounts
)
})
it('multiple spaces not detected as a word', () => {
const expectedCounts = new Map(
Object.entries({ multiple: 1, whitespaces: 1 })
)
expect(count(' multiple whitespaces')).toEqual(expectedCounts)
})
it('alternating word separators not detected as a word', () => {
const expectedCounts = new Map(Object.entries({ one: 1, two: 1, three: 1 }))
expect(count(",\n,one,\n ,two \n 'three'")).toEqual(expectedCounts)
})
it('quotation for word with apostrophe', () => {
const expectedCounts = new Map(Object.entries({ can: 1, "can't": 2 }))
expect(count("can, can't, 'can't'")).toEqual(expectedCounts)
})
it('handles properties that exist on Objects prototype', () => {
const expectedCounts = new Map(
Object.entries({
reserved: 1,
words: 1,
like: 1,
constructor: 1,
and: 1,
tostring: 1,
ok: 1,
})
)
expect(count('reserved words like constructor and toString ok?')).toEqual(
expectedCounts
)
})
})
+12
View File
@@ -0,0 +1,12 @@
export const count = (sentence: string): Map<string, number> =>
sentence
.toLowerCase()
.trim()
.replace(/^'(.*?)'$/, '$1')
.split(/[^a-zA-Z0-9']/)
.map(value => value.trim().replace(/^'(.*?)'$/, '$1'))
.filter(Boolean)
.reduce(
(acc, word) => acc.set(word, (acc.get(word) || 0) + 1),
new Map<string, number>()
);
File diff suppressed because it is too large Load Diff