import { useState, useCallback, useEffect } from "react"; import { KeyRound, Lock, Unlock } from "lucide-react"; function vigenere(text, key, mode) { const keyChars = key.toUpperCase().replace(/[^A-Z0-9]/g, ""); if (keyChars.length === 0) return ""; return text .split("") .map((ch, i) => { if (ch === " ") return " "; // 英文字母 A-Z / a-z if (/[a-zA-Z]/.test(ch)) { const upper = ch.toUpperCase(); const base = "A".charCodeAt(0); const shift = (keyChars.charCodeAt(i % keyChars.length) - 65) % 26; if (mode === "encrypt") { return String.fromCharCode(((upper.charCodeAt(0) - base + shift) % 26) + base); } else { return String.fromCharCode(((upper.charCodeAt(0) - base - shift + 26) % 26) + base); } } // 数字 0-9 if (/[0-9]/.test(ch)) { const num = parseInt(ch); const shift = parseInt(keyChars[i % keyChars.length]) % 10; if (mode === "encrypt") { return String((num + shift) % 10); } else { return String((num - shift + 10) % 10); } } // 中文及其他字符:按 Unicode 偏移,用数字的偏移量 const code = ch.charCodeAt(0); const shift = (keyChars.charCodeAt(i % keyChars.length) - 48) % 256; if (mode === "encrypt") { return String.fromCharCode(code + shift); } else { return String.fromCharCode(code - shift); } }) .join(""); } export default function VigenereCipher() { const [plaintext, setPlaintext] = useState(""); const [ciphertext, setCiphertext] = useState(""); const [key, setKey] = useState(""); const handlePlaintextChange = useCallback( (e) => { const val = e.target.value; setPlaintext(val); if (key.trim()) { setCiphertext(vigenere(val, key, "encrypt")); } else { setCiphertext(""); } }, [key] ); const handleCiphertextChange = useCallback( (e) => { const val = e.target.value; setCiphertext(val); if (key.trim()) { setPlaintext(vigenere(val, key, "decrypt")); } else { setPlaintext(""); } }, [key] ); const handleKeyChange = useCallback((e) => { const val = e.target.value.replace(/[^a-zA-Z0-9 ]/g, "").toUpperCase(); setKey(val); }, []); useEffect(() => { if (plaintext && key.trim()) { setCiphertext(vigenere(plaintext, key, "encrypt")); } }, [key, plaintext]); useEffect(() => { if (ciphertext && key.trim()) { setPlaintext(vigenere(ciphertext, key, "decrypt")); } }, [key, ciphertext]); return (
支持中文 · 英文自动大写 · 密钥支持字母 + 数字