Przejdź do treści

Szyfr Cezara w JavaScript

Cała funkcja mieści się na jednym ekranie i działa w każdej przeglądarce. Skopiuj ją albo wpisz własny tekst i zobacz, co kod robi z każdą literą.

caesar.js
function caesar(text, shift) {    let result = "";    for (const char of text) {        if (/[a-z]/i.test(char)) {            const base = char <= "Z" ? 65 : 97;            const code = char.charCodeAt(0) - base;            const index = ((code + shift) % 26 + 26) % 26;            result += String.fromCharCode(index + base);        } else {            result += char;        }    }    return result;} console.log(caesar("Witaj świecie!", 3));// Zlwdm śzlhflh!
reklama

Jak uruchomić kod

Najszybciej w przeglądarce: naciśnij F12, otwórz kartę Konsola, wklej kod i naciśnij Enter. Poza przeglądarką zapisz go jako caesar.js i użyj Node.js:

Terminal
node caesar.js

Jeśli sam szyfr jest dla ciebie nowy, zajrzyj do przewodnika, w którym nie ma kodu.

Jak działa ten kod

Pętla for...of czyta tekst znak po znaku, a wyrażenie regularne wybiera litery od A do Z, wielkie i małe. charCodeAt(0) podaje numer litery: 87 dla W, 119 dla w. Po odjęciu 65 lub 97 dostajesz miejsce w alfabecie, od 0 do 25.

Po dodaniu przesunięcia modulo zawija wynik, więc przy przesunięciu 3 litera Z trafia na C. String.fromCharCode robi z liczby z powrotem literę.

Cała reszta idzie gałęzią else i się nie zmienia. Dotyczy to także polskich liter, bo wyrażenie regularne ich nie obejmuje, dlatego „ś” w przykładzie zostaje na miejscu.

Deszyfrowanie w JavaScript

Druga funkcja nie jest potrzebna. Odszyfrowanie to takie samo przesunięcie w drugą stronę, więc wystarczy podać liczbę ujemną:

JavaScript
console.log(caesar("Zlwdm śzlhflh!", -3));// Witaj świecie!

Stąd dodatkowe + 26 we wzorze. W JavaScript % zachowuje znak lewej liczby, więc -3 % 26 to -3 i String.fromCharCode zwróciłby zły znak. Po dodaniu 26 i ponownym modulo wychodzi 23, czyli A wraca na X. W wersji w Pythonie robi to sam operator %.

Szyfr Cezara na stronie WWW

To kompletna strona: zapisz ją jako plik .html i otwórz w przeglądarce. Wynik zmienia się w trakcie pisania, a wszystko dzieje się na twoim komputerze.

HTML
<textarea id="text"></textarea><input id="shift" type="number" value="3"><output id="result"></output> <script>    // Tutaj wklej funkcję caesar     const text = document.querySelector("#text");    const shift = document.querySelector("#shift");    const result = document.querySelector("#result");     function update() {        result.textContent = caesar(text.value, Number(shift.value));    }     text.addEventListener("input", update);    shift.addEventListener("input", update);</script>

Dwa szczegóły są tu ważne. Wartość pola to zawsze napis, więc przesunięcie przechodzi przez Number(). Wynik trafia na stronę przez textContent, bo innerHTML wykonałoby każdy HTML wpisany w pole.

Narzędzie wiersza poleceń w Node.js

Zastąp dwie ostatnie linijki caesar.js tym kodem, a przesunięcie i tekst będą pochodzić z wiersza poleceń:

JavaScript
const [shift, ...words] = process.argv.slice(2);console.log(caesar(words.join(" "), Number(shift))); // node caesar.js 3 Witaj// Zlwdm

Łamanie szyfru metodą brute force

Przy 26 literach do sprawdzenia jest tylko 25 przesunięć, więc krótka pętla odczyta wiadomość bez klucza. Wystarczy znaleźć w wynikach linijkę, która ma sens:

JavaScript
function crack(text) {    for (let shift = 1; shift < 26; shift++) {        console.log(shift, caesar(text, -shift));    }} crack("Zlwdm śzlhflh!");// 1 Ykvcl śykgekg!// 2 Xjubk śxjfdjf!// 3 Witaj świecie!// ...

Więcej o tej metodzie przeczytasz w artykule o ataku brute force, a łamacz online zrobi to samo w przeglądarce.

Krótsza wersja z replace

replace z globalnym wyrażeniem regularnym wywołuje twoją funkcję dla każdej litery, a resztę zostawia w spokoju. Pętla i else nie są już potrzebne.

JavaScript
const caesar = (text, shift) =>    text.replace(/[a-z]/gi, (char) => {        const base = char <= "Z" ? 65 : 97;        const code = char.charCodeAt(0) - base;        return String.fromCharCode(((code + shift) % 26 + 26) % 26 + base);    });

Szyfr Cezara z polskimi znakami

Żeby przesuwać także ą, ć czy ż, zapisz alfabet w napisie i szukaj każdego znaku przez indexOf(). To ten sam alfabet, 35 znaków, którego używa nasze narzędzie:

JavaScript
const ALPHABET = "aąbcćdeęfghijklłmnńoópqrsśtuvwxyzźż"; function caesarAlphabet(text, shift) {    const size = ALPHABET.length;    let result = "";    for (const char of text) {        const position = ALPHABET.indexOf(char.toLowerCase());        if (position === -1) {            result += char;        } else {            const next = ALPHABET[((position + shift) % size + size) % size];            result += char === char.toLowerCase() ? next : next.toUpperCase();        }    }    return result;} console.log(caesarAlphabet("Zażółć gęślą jaźń", 3));// Acbrńę jhvnć łcąp

Zawijanie korzysta teraz z długości alfabetu, więc nie musisz nigdzie wpisywać 35. Wynik możesz porównać w narzędziu szyfru Cezara po wybraniu polskiego alfabetu.

Szyfrowanie pliku tekstowego

W Node.js odczyt i zapis pliku to po jednej linijce. Ten kod używa import, więc nazwij plik caesar.mjs albo ustaw "type": "module" w package.json.

JavaScript
import { readFileSync, writeFileSync } from "node:fs"; const text = readFileSync("message.txt", "utf8");writeFileSync("encrypted.txt", caesar(text, 3));

Gotowa biblioteka

Jeśli potrzebujesz szyfru w projekcie i nie chcesz go utrzymywać, nasza biblioteka caesar-cipher-js nie ma zależności i zawiera typy TypeScript. Zainstaluj ją przez npm install caesar-cipher-js:

JavaScript
import { encrypt, decrypt } from "caesar-cipher-js"; console.log(encrypt("Witaj świecie!", 3));// Zlwdm śzlhflh!console.log(decrypt("Zlwdm śzlhflh!", 3));// Witaj świecie!

Testowanie kodu

Node.js ma wbudowany moduł asercji, więc kilka linijek wyłapie większość błędów: przejście poza Z, zachowanie wielkości liter, pozostawienie interpunkcji i powrót do tekstu wyjściowego. Jeśli wszystko gra, program wypisze OK.

JavaScript
import assert from "node:assert/strict"; assert.equal(caesar("ABC", 3), "DEF");assert.equal(caesar("xyz", 3), "abc");assert.equal(caesar("Hello, World!", 5), "Mjqqt, Btwqi!");assert.equal(caesar(caesar("JavaScript", 7), -7), "JavaScript");assert.equal(caesar("A", -27), "Z");assert.equal(caesar("é", 3), "é");console.log("OK");

Najczęstsze błędy

Najczęstszy to przesunięcie zostawione jako napis: 7 + "3" daje "73", a program po cichu zwraca złą literę. Drugi to % przy ujemnym przesunięciu, o czym była mowa wyżej. Nie używaj też innerHTML do pokazania wyniku, bo tekst pochodzi od użytkownika.

Najczęstsze pytania

Czy to działa w każdej przeglądarce?

Tak, wszystkie współczesne przeglądarki obsługują użytą tu składnię. Kod z tej strony uruchomiliśmy w Node.js 25, a stronę WWW sprawdziliśmy w przeglądarce.

Czy mogę tym chronić prawdziwe dane?

Nie. Pętla pokazana wyżej łamie ten szyfr w kilka sekund. Używaj go do nauki i łamigłówek. Do prawdziwych danych przeglądarki i Node.js udostępniają współczesne szyfrowanie przez Web Crypto API.

Jak sprawdzić, czy wynik jest poprawny?

Wpisz ten sam tekst i przesunięcie w narzędziu szyfru Cezara i porównaj. Ze swoich testów możesz też wywołać darmowe REST API.

Co dalej