
本文介绍如何修改现有代码,使自定义语言转换器支持多行输入(如换行符 \n),通过使用 textarea 获取输入、按行分割再逐行处理,确保每行语法正确转换并保留原始换行结构。
本文介绍如何修改现有代码,使自定义语言转换器支持多行输入(如换行符 `\n`),通过使用 `textarea` 获取输入、按行分割再逐行处理,确保每行语法正确转换并保留原始换行结构。
要让您的自定义语言转换器支持多行输入(例如用户在 <textarea> 中输入含换行的代码),关键在于:不能将整个多行字符串直接传入原 lexer() 函数进行引号分割——因为当前正则 /".*?"/g 会跨行匹配(.*? 默认不匹配换行符),且原 out() 函数未考虑行边界,导致逻辑错乱。此外,HTML 中应改用 <textarea> 替代单行 <input>,以天然支持换行输入。
✅ 正确做法:按行处理(Line-by-Line Processing)
首先,将输入按行切分,再对每一行独立执行「词法分析 → 解析 → 输出拼接」流程。以下是优化后的核心函数:
// 1. 保持 lexer 不变(仅处理单行内引号)
function lexer(code) {
const regex = /"(.*?)"/g;
return code.split(regex);
}
// 2. parse 简化为纯字符串替换(无副作用)
function parse(input) {
return input
.replace(/new/g, "let")
.replace(/is/g, "=")
.replace(/say/g, "console.log")
.replace(/shout/g, "alert");
}
// 3. out 修正:只处理单行 token 数组,避免跨行拼接错误
function out(arr) {
let code = "";
for (let i = 0; i < arr.length; i++) {
if (i % 2 === 0) {
code += parse(arr[i]);
} else {
code += `"${parse(arr[i])}"`;
}
}
return code;
}
// 4. 新增 convertor:主入口,按行处理 + 保留换行
function convertor(input) {
const lines = input.split(/\r?\n/); // 兼容 \n 和 \r\n
return lines
.map(line => {
if (!line.trim()) return ""; // 跳过空行
return out(lexer(line));
})
.join("\n");
}? 使用示例与 HTML 集成
<textarea id="sparkText" placeholder="输入您的自定义语言(支持多行): new dog is "dog" new cat is "cat""></textarea> <button onclick="update()">转换</button> <pre id="jsText"></pre>
function update() {
const input = document.getElementById("sparkText").value;
const jsCode = convertor(input);
document.getElementById("jsText").textContent = jsCode;
}⚠️ 重要注意事项:
- 原 convert() 函数中手动包裹反引号 `...` 是错误的——它会把换行符转义为字面量 \n,破坏结构;应直接传入原始字符串。
- parse() 中的 .replace() 应加全局标志 g(如 /new/g),否则仅替换首个匹配项(如 new a is "x"\nnew b is "y" 中第二个 new 不会被替换)。
- lexer() 对空字符串或无引号行仍可安全工作(split() 返回 [line]),无需额外校验。
- 若需更健壮语法(如嵌套引号、注释、运算符优先级),建议后续引入状态机或正式 parser,而非正则主导的简单替换。
最终效果:
输入
new dog is "dog" new cat is "cat" say "Hello"
输出
立即学习“Java免费学习笔记(深入)”;
let dog = "dog" let cat = "cat" console.log "Hello"
——每行独立转换,结构清晰,完全支持多行交互。


















