Inhalt
Die Fakten:
Plattform: | codewars.com |
Name: | Word a10n (abbreviation) |
Level: | 6 kyu |
Sprache: | TypeScript |
Beschreibung:
The word i18n
is a common abbreviation of internationalization
in the developer community, used instead of typing the whole word and trying to spell it correctly. Similarly, a11y
is an abbreviation of accessibility
.
Write a function that takes a string and turns any and all "words" (see below) within that string of length 4 or greater into an abbreviation, following these rules:
- A "word" is a sequence of alphabetical characters. By this definition, any other character like a space or hyphen (eg. "elephant-ride") will split up a series of letters into two words (eg. "elephant" and "ride").
- The abbreviated version of the word should have the first letter, then the number of removed characters, then the last letter (eg. "elephant ride" => "e6t r2e").
Example
abbreviate("elephant-rides are really fun!")
// ^^^^^^^^*^^^^^*^^^*^^^^^^*^^^*
// words (^): "elephant" "rides" "are" "really" "fun"
// 123456 123 1 1234 1
// ignore short words: X X
// abbreviate: "e6t" "r3s" "are" "r4y" "fun"
// all non-word characters (*) remain in place
// "-" " " " " " " "!"
=== "e6t-r3s are r4y fun!"
Quelle: codewars.com
Lösung
Pseudo-Code
Es gibt wie immer viele Varianten, hier ist eine meiner.
Erst die Lösungsschritte in Pseudo-Code. Los geht’s:
Lösungsschritte
Schritt 1
Ich würde mir zuerst jeweils die Wörter und alles was kein Buchstabe ist jeweils in ein Array speichern. So dass ich beides getrennt habe.
Schritt 2
Dann können wir durch das Wörter-Array loopen
Schritt 3
Wenn das Wort zu kurz ist, kommt es unverändert zurück ins Array
Schritt 4
Ansonsten der erste Buchstabe des Wortes, dann die Länge -2 und dann der letzte Buchstabe
Schritt 5
Dann müssen wir noch die Nicht-Buchstaben wieder einfügen
Code
Geil. Übersetzen wir unseren Pseudo-Code in TypeScript:
Lösungsschritte
Meine erste Zeile:
export function abbreviate(str: string): string {
Wörter und Nicht-Buchstaben in 2 getrennte Arrays packen:
const nonletters = str.match(/[^a-z]/gi) || [];
const words = str.split(/[^a-z]/gi);
Ich verwende hier eine Regular Expression. Die Methode .match() verwenden wir um alles was kein Buchstabe ist, im Array nonLetters
zu speichern. || []
sagt TypeScript, wenn nichts gefunden wird, ist nonLetters
ein leeres Array. ^
negiert den Ausdruck in den eckigen Klammern.
Mit .split() nutzen wir genau die gleiche RegEx. Aber .split() entfernt alles, was der RegEx entspricht.
Dann der Loop:
words
.map((word, i) => {
Da ich hier für jedes Element etwas Neues zurück haben möchte, verwende ich .map().
Jetzt initialisiere ich mir eine Variable für den String, den ich zurück ins Array geben möchte:
let newWord = "";
Wenn das Wort zu kurz ist, kann ich es direkt in dieser Variablen speichern:
if (word.length <= 3) newWord = word;
Wenn es mehr als 3 Buchstaben hat, initialisiere ich mir ein paar weitere Variablen um den Code lesbarer zu machen:
else {
const first = word[0];
const middle = word.slice(1, word.length - 1).length;
const last = word.slice(-1);
Ich erstelle mir also schon mal Anfang, Mitte und Ende meines neuen Strings.
Jetzt das Ganze zusammenführen:
newWord = first + middle + last;
}
Dann die Nicht-Buchstaben wieder dran:
newWord += nonletters[i] || "";
Das neue Word zurück ins Array:
return newWord;
})
Und das Array wieder in einen String umwandeln:
.join("");
}
Jetzt noch das Resultat zurückgeben:
Da wir schön vorbildlich gechained haben, können wir einfach das return
-Statement direkt oben vor unserem Loop platzieren.
export function abbreviate(str: string): string {
const nonletters = str.match(/[^a-z]/gi) || [];
const words = str.split(/[^a-z]/gi);
//! hier einfach das `return` direkt davor
return words
.map((word, i) => {
let newWord = "";
// ...
})
.join("");
}
Voilá! 💪
Komplettlösung
export function abbreviate(str: string): string {
const nonletters = str.match(/[^a-z]/gi) || [];
const words = str.split(/[^a-z]/gi);
return words
.map((word, i) => {
let newWord = "";
if (word.length <= 3) newWord = word;
else {
const first = word[0];
const middle = word.slice(1, word.length - 1).length;
const last = word.slice(-1);
newWord = first + middle + last;
}
newWord += nonletters[i] || "";
return newWord;
})
.join("");
}