Codewars Lösung | Word a10n (abbreviation)


coden
Codewars. Achieve mastery through challenge.
Daniel Kaser|14. Februar 2024
4 min.

Inhalt

  1. Die Fakten
  2. Beschreibung
  3. Lösung
    1. Pseudo-Code
    2. Code
  4. Feedback

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á! 💪

Fragen?

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("");
}

Feedback

Schreib mir!