ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

freeCodeCamp 每日编程挑战解读:用字符编码与模运算实现凯撒密码解译(Message Decoder)

freeCodeCamp 每日编程挑战解读:用字符编码与模运算实现凯撒密码解译(Message Decoder) freeCodeCamp 每日编程挑战解读用字符编码与模运算实现凯撒密码解译Message Decoder【免费下载链接】freeCodeCampfreeCodeCamp.orgs open-source codebase and curriculum. Learn math, programming, and computer science for free.项目地址: https://gitcode.com/GitHub_Trending/fr/freeCodeCamp本文以 freeCodeCamp 课程仓库中 Daily Coding Challenges 系列JavaScript的第 12 题 Challenge 12: Message Decoder 为主体完整覆盖该题的原始题目约束、四组官方测试用例与参考解答并结合仓库中的挑战类型定义、课程结构与出题管线源码深入讲解如何用charCodeAt/fromCharCode加模运算% 26实现支持正负偏移、自动环绕且保留大小写的凯撒密码解码。读完本文你能独立写出该函数、理解偏移量取模消除的原理并了解这道题在 freeCodeCamp 课程体系中的落地位置。题目在仓库中的位置与出处本题对应仓库中的课程文档 Challenge 12: Message Decoder其 front matter 声明了以下元数据id: 68216ef80f957572e7c340c5 title: Challenge 12: Message Decoder challengeType: 28 dashedName: challenge-12challengeType: 28并非随意编号。在共享包的 challenge-types.ts 中可以看到const jsLab 26; const pyLab 27; const dailyChallengeJs 28; const dailyChallengePy 29;即 28 是dailyChallengeJs类型。同一文件还规定该类型的视图与提交方式// determine the component view for each challenge export const viewTypes { ... [dailyChallengeJs]: classic, // 使用经典编辑器视图 ... }; // determine the type of submit function to use on completion export const submitTypes { ... [dailyChallengeJs]: tests, // 通过跑断言测试判定通过 ... };从源码结构看dailyChallengeJs会被getIsDailyCodingChallenge同文件 L187-L188识别为每日编程挑战并用viewTypes中的classic视图在客户端渲染完成判定走tests提交路径——也就是说本文后面的四组assert.equal用例就是判题依据本身。该题的排序信息记录在 block 结构文件dashedName: daily-coding-challenges-javascript中68216ef80f957572e7c340c5排在 Challenge 11: Mile Pace 之后、Challenge 13: Unnatural Prime 之前title为 Challenge 12: Message Decoder。该结构文件同时声明了usesMultifileEditor: true、helpCategory: JavaScript、blockLayout: legacy-challenge-list等块级配置。值得注意的一点该 block 配置中isUpcomingChange: true且 api/src/daily-coding-challenge 的 README 说明每日挑战的信息接口独立于主 API——从目录结构routes/、schemas/、utils/推断线上每日挑战是按日期轮播投放的挑战集而本仓库中以固定文件形式存放的是题库本体。因此以下讲解以题库中的题目文件为准。题目原文给定密文与偏移量还原明文题目的原始描述description 小节为Given a secret message string, and an integer representing the number of letters that were used to shift the message to encode it, return the decoded string.A positive number means the message was shifted forward in the alphabet.A negative number means the message was shifted backward in the alphabet.Case matters, decoded characters should retain the case of their encoded counterparts.Non-alphabetical characters should not get decoded.翻译成工程语言函数签名是decode(message: string, shift: number): string约束有四条shift为正数编码时字母在字母表中向前移动了shift位如a → eshift为负数编码时字母向后移动了|shift|位大小写必须保留编码字符是大写解码结果就是大写反之亦然非字母字符原样透传空格、标点、数字等一律不做变换。这本质上是一个双向凯撒密码编码是字母平移解码就是反向平移。官方测试用例与断言题目文档的 hints 小节给出了四组官方断言它们同时覆盖了正偏移、大偏移、负偏移、混合大小写和符号透传等关键场景输入message输入shift期望输出覆盖点Xlmw mw e wigvix qiwweki.4This is a secret message.正偏移、含句号Byffi Qilfx!20Hello World!大偏移20 等价于 -6Zqd xnt njzx?-1Are you okay?负偏移、含问号oannLxmnLjvy9freeCodeCamp混合大小写、无空格对应的断言写法即判题时执行的testString内容assert.equal(decode(Xlmw mw e wigvix qiwweki., 4), This is a secret message.); assert.equal(decode(Byffi Qilfx!, 20), Hello World!); assert.equal(decode(Zqd xnt njzx?, -1), Are you okay?); assert.equal(decode(oannLxmnLjvy, 9), freeCodeCamp);种子代码seed-contents是一个只返回原文的占位实现function decode(message, shift) { return message; }解题目标就是替换return message;让上述四个断言全部通过。核心原理字符编码差值 取模消除字母在 Unicode 中是连续区间ASCII/Unicode 中A到Z、a到z各是一个连续编号区间A的码位是 65a是 97。因此字母可以无损地映射为 0–25 的槽位const base char char.toLowerCase() ? a.charCodeAt(0) : A.charCodeAt(0); // base 为 97小写或 65大写 const slot char.charCodeAt(0) - base; // 0 表示 a/A25 表示 z/Z编码与解码互为反向平移设明文字母的槽位为p编码后的槽位为c则正偏移编码c (p shift) % 26所以解码要减去shiftp (c - shift) mod 26负偏移编码c (p - |shift|) % 26解码要加上|shift|——同样可写成(c - shift) mod 26此时shift为负减负等于加正统一公式就是p (c - shift) mod 26这正是题目文档中官方解答采用的形式const offset (charCode - base - shift 26) % 26;这里有一个 JavaScript 特有的关键细节%取余保留被除数的符号负数取余会得到负值如(-3) % 26 -3。因此在减shift之后先 26保证表达式落为非负数再取模从而得到 0–25 的合法槽位。 26足以覆盖单个字母一次平移的边界因为c - shift ∈ (-26, 26)区间内时加一次 26 必为非负。延伸若要支持任意大小的shift例如shift 100需要先把shift归一化shift ((shift % 26) 26) % 26。题目给出的shift 20在 (-26, 26) 内所以官方解答无需这一步。参考解答逐行拆解题目文档 solutions 小节给出的官方解答function decode(message, shift) { return message.split().map(char { if (/[a-zA-Z]/.test(char)) { const base char char.toLowerCase() ? a.charCodeAt(0) : A.charCodeAt(0); const charCode char.charCodeAt(0); const offset (charCode - base - shift 26) % 26; return String.fromCharCode(base offset); } else { return char; } }).join(); }逐行说明message.split()把字符串拆成单字符数组配合map对每个字符独立处理——这是逐字符变换 重组的函数式惯用写法/[a-zA-Z]/.test(char)只处理纯 ASCII 字母。非字母空格、.、!、?等走else分支原样返回满足约束 4。题目数据只含 ASCII 字母所以用[a-zA-Z]而非\p{L}是精确且安全的char char.toLowerCase()判断大小写并选定基准码base97 或 65。这一步保证解码后的字符与密文字符大小写一致满足约束 3(charCode - base - shift 26) % 26核心槽位计算如上一节所述String.fromCharCode(base offset)把槽位映射回字符大小写由base决定.join()把字符数组拼回字符串。用第一组用例手工验证一下shift 4时的XX.charCodeAt(0) 88base 65槽位c 23X 是第 24 个字母offset (23 - 4 26) % 26 45 % 26 19String.fromCharCode(65 19)T。✓负偏移用例Zshift -1offset (25 - (-1) 26) % 26 52 % 26 0→A即Zqd → Are。✓大偏移用例shift 20的Boffset (1 - 20 26) % 26 7 % 26 7→H。✓ 可见 20 位的前移编码等价于解码时后移 6 位模 26 的周期性让两者完全等价。验证思路与等价写法由于submitTypes[dailyChallengeJs] tests本题的通过标准就是四组assert.equal全部为真。自行验证时可以直接把测试用例粘到 Node 或浏览器控制台跑一遍仓库中同类挑战的数据在入库时还会经过客户端侧的 Joi 结构校验参见 daily-coding-challenge-validator.ts其中tests数组要求每项必须含text与testString两个字段testString正是上述assert.equal(...)字符串这从管线角度印证了断言即判题的设计。在等价实现层面还有几种常见变体供对照理解查表法预构造abcdefghijklmnopqrstuvwxyz字符串用indexOf定位槽位再按下标取字符正则替换法message.replace(/[a-zA-Z]/g, fn)跳过显式split/map/join先归一化 shiftshift ((shift % 26) 26) % 26之后解码公式统一为(slot - shift 26) % 26。三者与官方解答在题目给定的输入域ASCII 字母 整数 shift内行为一致官方解答的优势在于不引入额外数据结构、一行表达式完成核心计算。小结这道 Message Decoder 是 freeCodeCamp JavaScript 每日挑战题库中的一个典型字符串处理题其教学价值集中在三个可迁移的技能点用charCodeAt/fromCharCode在字符与数字之间自由转换、用% 26实现字母表环绕、以及正确处理 JavaScript 取余的负数语义。题目文件位于 curriculum/challenges/english/blocks/daily-coding-challenges-javascript/68216ef80f957572e7c340c5.md挑战类型与判题方式定义在 packages/shared/src/config/challenge-types.ts块级排序与编辑器配置见 curriculum/structure/blocks/daily-coding-challenges-javascript.json可按此路径继续深入研究该题库的组织方式。【免费下载链接】freeCodeCampfreeCodeCamp.orgs open-source codebase and curriculum. Learn math, programming, and computer science for free.项目地址: https://gitcode.com/GitHub_Trending/fr/freeCodeCamp创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表