Files
exercise-typescript/typescript/pig-latin/pig-latin.ts
2025-04-20 15:23:43 +02:00

94 lines
2.3 KiB
TypeScript

const vowels = ['A', 'E', 'I', 'O', 'U']
const consonants = [
'B',
'C',
'D',
'F',
'G',
'H',
'J',
'K',
'L',
'M',
'N',
'P',
'Q',
'R',
'S',
'T',
'V',
'W',
'X',
'Y',
'Z',
]
const startsWiths = ['XR', 'YT', 'AY']
const rule1 = (word: string) =>
// If a word begins with a vowel, or starts with `"xr"` or `"yt"`,
// add an `"ay"` sound to the end of the word.
vowels.concat(startsWiths).some(s => word.toUpperCase().startsWith(s))
? `${word}ay`
: word
const rule2RegExp = new RegExp(`^([${consonants.join('')}]+)(.*)`, 'i')
const rule2 = (word: string): string =>
// If a word begins with a one or more consonants, first move
// those consonants to the end of the word and then add an `"ay"`
// sound to the end of the word.
word.replace(
rule2RegExp,
(_, match, rest) => `${rest}${match}${match ? 'ay' : ''}`,
)
const rule3RegExp = new RegExp(`^(qu|[${consonants.join('')}]*qu)(.*)`, 'i')
const rule3 = (word: string): string =>
// If a word starts with zero or more consonants followed by `"qu"`,
// first move those consonants (if any) and the `"qu"` part to the end
// of the word, and then add an `"ay"` sound to the end of the word.
word.replace(
rule3RegExp,
(_, match, rest) => `${rest}${match}${match ? 'ay' : ''}`,
)
const rule4RegExp = new RegExp(`^([${consonants.join('')}]+)(y.*)`, 'i')
const rule4 = (word: string): string =>
// If a word starts with one or more consonants followed by `"y"`,
// first move the consonants preceding the `"y"`to the end of the word,
// and then add an `"ay"` sound to the end of the word.
word.replace(
rule4RegExp,
(_, match, rest) => `${rest}${match}${match ? 'ay' : ''}`,
)
const applyRule =
(rule: (word: string) => string) =>
({
originalWord,
hasChanged,
}: {
originalWord: string
hasChanged: boolean
}) => {
if (hasChanged) return { originalWord, hasChanged }
const word = rule(originalWord)
return { originalWord: word, hasChanged: word !== originalWord }
}
export const translate = (text: string): string => {
return text
.split(' ')
.filter(Boolean)
.map(word => ({ originalWord: word, hasChanged: false }))
.map(applyRule(rule1))
.map(applyRule(rule3))
.map(applyRule(rule4))
.map(applyRule(rule2))
.map(({ originalWord }) => originalWord)
.join(' ')
}