Codewars Lösung | IP Address to Number


coden
Codewars. Achieve mastery through challenge.
Daniel Kaser|8. Mai 2024
3 min.

Inhalt

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

Die Fakten:

Plattform:codewars.com
Name:IP Address to Number
Level:6 kyu
Sprache:TypeScript

Beschreibung:

An IPv4 address is a 32-bit number that identifies a device on the internet.

While computers read and write IP addresses as a 32-bit number, we prefer to read them in dotted-decimal notation, which is basically the number split into 4 chunks of 8 bits, converted to decimal, and delmited by a dot.

In this kata, you will create the function ipToNum (or ip_to_num, depending on the language) that takes an ip address and converts it to a number, as well as the function numToIp (or num_to_ip) that takes a number and converts it to an IP address string. Input will always be valid.

Conversion Example

//original IP address
192.168.1.1

//breaks down into 4 binary octets
11000000 . 10101000 . 00000001 . 00000001

//which are merged together (unsigned 32-bit binary)
11000000101010000000000100000001

//and finally converted to base 10
3232235777

Note that the binary octets are unsigned (so we can't have negative numbers).

Be careful: JavaScript does bitwise arithmetic on *signed* 32-bits integers.

Examples

ipToNum / ip_to_num

'192.168.1.1' converts to 3232235777
'10.0.0.0'    converts to  167772160
'176.16.0.1'  converts to 2953838593

numToIp / num_to_ip

3232235777 converts to '192.168.1.1'
 167772160 converts to    '10.0.0.0'
2953838593 converts to  '176.16.0.1'

Quelle: codewars.com

Lösung

Pseudo-Code

Wie immer gibt's reichlich Varianten, hier ist eine meiner.

Erst die Lösungsschritte in Pseudo-Code. Los geht’s:

Lösungsschritte

Als Erstes die Funktion ipToNum()

Schritt 1

Wir entfernen die Punkte und wandeln den String in ein Array um.

Schritt 2

Dann loopen wir durch das Array und wandeln jedes Element in seine 8-stellige Binär-Version um.

Schritt 3

Jetzt können wir die Elemente wieder zu einem String zusammenführen und diesen 32-Bit-Binär-String dann in einen Integer umwandeln.

Dann die Funktion numToIP()

Schritt 4

Zuerst wandeln wir die Input-Zahl in eine 32-stellige Binär-Zahl um.

Schritt 5

Dann teilen wir diese in 4 Teile bzw. Bytes à 8 Zeichen bzw. Bits.

Schritt 6

Diese 4 Bytes wandeln wir dann jeweils in ein Integer um.

Schritt 7

Am Ende wandeln wir das Array in einen String mit einem Punkt als Trennzeichen.

Code

Geil. Übersetzen wir unseren Pseudo-Code in TypeScript:

Lösungsschritte
Die erste Zeile meiner ipToNum()-Funktion:
export function ipToNum(ip: string): number {
Als Erstes machen wir aus dem String die 8-stellige Binär-Version ohne Punkte:
const binary32bit = ip
  .split(".")
  .map(Number)
  .map((num) => num.toString(2).padStart(8, "0"))
  .join("");

Das geht hier wunderbar mit Method-Chaining. .map(Number) loopt hier ein Mal durch alle Elemente und wandelt die String-Zahlen in richtige Zahlen um. .toString(2) macht aus einer Zahl ihre Binär-Version. Mit .padStart(8, “0”) sorgen wir dafür, dass wir immer eine 8-stelliege Binärzahl bzw. ein Byte erhalten. Und mit .join() fügen wir alle 4 Bytes zu einer 32-stelligen Zahl zusammen.

Nur noch in einen Integer konvertieren und zurückgeben:
  return parseInt(binary32bit, 2);
}

Das war sie schon, die ipToNum()-Funktion. Weiter geht’s mit der numToIp()-Funktion.

Die erste Zeile meiner numToIp()-Funktion:
export function numToIp(num: number): string {
Input-Zahl in eine 32-stellige Binärzahl umwandeln:
const binary32bit = num.toString(2).padStart(32, "0");

Um sicherzustellen, dass wir 32-Bits bekommen, fügen wir mit .padStart(32, "0") wieder eventuell noch fehlende Nullen hinzu.

Dann die Binärzahl in 4 Teile/Bytes á 8 Bits teilen:
const bytes = ["", "", "", ""].map((_, i) => {
  const byteStart = i * 8;
  const byteEnd = (i + 1) * 8;
  return binary32bit.slice(byteStart, byteEnd);
});
Jetzt die Bytes in Integer umwandeln:
const nums = bytes.map((byte) => parseInt(byte, 2));
Zum Schluss das Ganze in einen String mit Punkten konvertieren und zurückgeben:
  return nums.join(".");
}
Voilá! 💪

Fragen?

Komplettlösung
export function ipToNum(ip: string): number {
  const binary32bit = ip
    .split(".")
    .map(Number)
    .map((num) => num.toString(2).padStart(8, "0"))
    .join("");

  return parseInt(binary32bit, 2);
}

export function numToIp(num: number): string {
  const binary32bit = num.toString(2).padStart(32, "0");

  const bytes = ["", "", "", ""].map((_, i) => {
    const byteStart = i * 8;
    const byteEnd = (i + 1) * 8;
    return binary32bit.slice(byteStart, byteEnd);
  });

  const nums = bytes.map((byte) => parseInt(byte, 2));

  return nums.join(".");
}

Feedback

Schreib mir!