Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions .idea/modules.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions .prettierrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"trailingComma": "es5",
"tabWidth": 4,
"semi": false,
"singleQuote": true
}
20 changes: 13 additions & 7 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,17 @@
"name": "frontend-exercise",
"version": "0.1.0",
"private": true,
"engines": {
"node": " >=18"
},
"dependencies": {
"@testing-library/jest-dom": "^5.11.4",
"@testing-library/react": "^11.1.0",
"@testing-library/user-event": "^12.1.10",
"react": "^17.0.1",
"react-dom": "^17.0.1",
"react-scripts": "4.0.1",
"web-vitals": "^0.2.4"
"@testing-library/jest-dom": "^6.4.2",
"@testing-library/react": "^15.0.4",
"@testing-library/user-event": "^14.5.2",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-scripts": "5.0.1",
"web-vitals": "^3.5.2"
},
"scripts": {
"start": "react-scripts start",
Expand All @@ -34,5 +37,8 @@
"last 1 firefox version",
"last 1 safari version"
]
},
"devDependencies": {
"prettier": "3.2.5"
}
}
34 changes: 23 additions & 11 deletions src/App.js
Original file line number Diff line number Diff line change
@@ -1,16 +1,28 @@
import { useEffect, useState } from 'react'
import { numberFromWord } from './utils/numberFromWord'

function App() {
const text = ''
const [value, setValue] = useState('one hundred twenty and one')
const [result, setResult] = useState(0)

useEffect(() => {
setResult(numberFromWord(value))
}, [value])

return (
<div>
<input type='text' />
<div>
<p>
Output: {text}
</p>
</div>
</div>
)
return (
<div>
<input
type="text"
defaultValue={value}
onChange={(e) => {
setValue(e.target.value)
}}
/>
<div>
<p>Output: {result}</p>
</div>
</div>
)
}

export default App
5 changes: 0 additions & 5 deletions src/App.test.js

This file was deleted.

40 changes: 40 additions & 0 deletions src/constants/words.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
export const words = {
zero: 0,
one: 1,
two: 2,
three: 3,
four: 4,
five: 5,
six: 6,
seven: 7,
eight: 8,
nine: 9,
ten: 10,
eleven: 11,
twelve: 12,
thirteen: 13,
fourteen: 14,
fifteen: 15,
sixteen: 16,
seventeen: 17,
eighteen: 18,
nineteen: 19,
twenty: 20,
thirty: 30,
forty: 40,
fifty: 50,
sixty: 60,
seventy: 70,
eighty: 80,
ninety: 90,
}

export const multipliers = {
hundred: 100,
thousand: 1000,
million: 1000000,
billion: 1000000000,
}

export const max = 999999999
export const min = 0
52 changes: 52 additions & 0 deletions src/utils/numberFromWord.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import {
words as wordDictionary,
multipliers as multipliersDictionary,
min,
max,
} from '../constants/words'

export const numberFromWord = (string) => {
string = string.toLowerCase().replace(/-|\s+and\s+/g, ' ')
let words = string.split(/\s+/)
let current = 0
let result = 0
let lastMultiplier = 1
let lastWasNumber = false
let lastNumber = 0

for (let word of words) {
if (wordDictionary.hasOwnProperty(word)) {
// exception for wordDictionary[word] === 0
let numberValue = wordDictionary[word]
if (lastWasNumber) {
if (
!(lastNumber >= 20 && lastNumber < 100 && numberValue < 10)
) {
return 'incorrect'
}
}
current = current + numberValue
lastWasNumber = true
lastNumber = numberValue
} else if (multipliersDictionary[word]) {
if (current === 0 && result === 0) {
return 'incorrect'
}
current = current * multipliersDictionary[word]
if (multipliersDictionary[word] > lastMultiplier) {
result = result + current
current = 0
}
lastMultiplier = multipliersDictionary[word]
lastWasNumber = false
} else {
return 'incorrect'
}
}

result = result + current
if (result < min || result > max) {
return 'incorrect'
}
return result
}
78 changes: 78 additions & 0 deletions src/utils/numberFromWord.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import { numberFromWord } from './numberFromWord'

describe('numberFromWord', () => {
describe('test outputs', () => {
it('zero => 0', () => {
const test = numberFromWord('zero')
expect(test).toBe(0)
})

it('one => 1', () => {
const test = numberFromWord('one')
expect(test).toBe(1)
})

it('one hundred => 100', () => {
const test = numberFromWord('one hundred')
expect(test).toBe(100)
})
it('one hundred twenty => 120', () => {
const test = numberFromWord('one hundred twenty')
expect(test).toBe(120)
})

it('three million one hundred thousand and ninety =≥ 3100090', () => {
const test = numberFromWord(
'three million one hundred thousand and ninety'
)
expect(test).toBe(3100090)
})

it('two thousand and forty five => 2045', () => {
const test = numberFromWord('two thousand and forty five')
expect(test).toBe(2045)
})

it('fifty four => 54', () => {
const test = numberFromWord('fifty four')
expect(test).toBe(54)
})
})

describe('test edge cases', () => {
it('one hundred-twenty => 120', () => {
const test = numberFromWord('one hundred-twenty')
expect(test).toBe(120)
})

it('ONE HUNDRED-TWENTY => 120', () => {
const test = numberFromWord('ONE HUNDRED-TWENTY')
expect(test).toBe(120)
})

it('ONE HUNDRED and TWENTY => 120', () => {
const test = numberFromWord('ONE HUNDRED and TWENTY')
expect(test).toBe(120)
})

it('one one => incorrect', () => {
const test = numberFromWord('one one')
expect(test).toBe('incorrect')
})

it('one one => incorrect', () => {
const test = numberFromWord('one one')
expect(test).toBe('incorrect')
})

it('one billion => incorrect', () => {
const test = numberFromWord('one billion')
expect(test).toBe('incorrect')
})

it('one billion => incorrect', () => {
const test = numberFromWord('minus one')
expect(test).toBe('incorrect')
})
})
})