基于Bash/sed/AWK实现TeX格式花括号解析与转换
用AWK实现TeX格式到Markdown的状态转换
我是数学背景,一直只用Plain TeX做文本编辑,哪怕是非数学内容也不用Word或Google Docs。但偶尔需要提交docx格式文件,之前得把TeX代码粘去Google Docs手动改了再导出,所以在.zshrc里写了个tex2doc的bash函数,用来处理欧洲重音这类简单转换:
tex2doc() { (tr '\n' ' ' < $1.tex) | sed 's/ /\n\t/g' | sed "s/\\\'e/é/g" | sed "s/\\\^o/ô/g" | sed "s/\\\'E/É/g" | sed 's/```/“‘/g' | sed "s/'''/’”/g" | sed 's/``/“/g' | sed "s/''/”/g" | sed 's/`/‘/g' | sed "s/'/’/g" | sed 's/\\\"//g' | sed 's/\\~n/ñ/g' | sed 's/\~/ /g' | sed 's/\\ / /g' | sed 's/\\-//g' | sed 's/\\c{c}/ç/g' | sed 's/\\\///g' | sed 's/---/—/g' | sed 's/--/–/g' > $1.txt }
现在还有更复杂的格式转换需求,要把TeX里的{\it ... }斜体、{\bf ... }粗体、{\sc ... }小型大写转成Markdown格式,具体规则:
- 遇到
{\it替换为_ - 遇到
{\bf替换为** - 遇到
{\sc替换为空字符串 - 遇到
}时,根据最近的标记对应替换:{\it对应_,{\bf对应**,{\sc对应空,同时要实现栈的弹出逻辑
试过Python词法分析器但觉得没必要,想找bash风格的方案,知道sed处理不了带状态的解析,求AWK的实现思路和方法。
AWK实现方案
AWK可以通过自定义数组模拟栈结构,处理这种需要状态跟踪的替换逻辑。下面是具体的实现代码,可以集成到你的tex2doc函数里:
#!/usr/bin/awk -f BEGIN { # 定义TeX命令到Markdown标记的映射 cmd_map["\\it "] = "_" cmd_map["\\bf "] = "**" cmd_map["\\sc "] = "" } { line = $0 i = 1 len = length(line) while (i <= len) { # 检查是否匹配{\it/{\bf/{\sc开头的命令 match(line, /^\{\\(it|bf|sc) /, m) if (RSTART == 1) { # 输出对应的Markdown标记 printf "%s", cmd_map["\\" m[1] " "] # 将当前命令压入栈 stack[++stack_ptr] = m[1] # 跳过匹配的字符长度 i += RLENGTH line = substr(line, RLENGTH + 1) len = length(line) continue } # 检查是否遇到闭合的} if (substr(line, i, 1) == "}") { if (stack_ptr > 0) { # 弹出栈顶的命令,输出对应的闭合标记 cmd = stack[stack_ptr--] printf "%s", (cmd == "it" ? "_" : (cmd == "bf" ? "**" : "")) } else { # 栈为空时直接输出}(处理不匹配的情况) printf "}" } i++ line = substr(line, 2) len = length(line) continue } # 其他字符直接输出,指针后移 printf "%s", substr(line, i, 1) i++ line = substr(line, 2) len = length(line) } printf "\n" }
集成到现有函数的方法
修改你的tex2doc函数,把AWK处理步骤加进去:
tex2doc() { (tr '\n' ' ' < $1.tex) | sed 's/ /\n\t/g' | sed "s/\\\'e/é/g" | sed "s/\\\^o/ô/g" | sed "s/\\\'E/É/g" | sed 's/```/“‘/g' | sed "s/'''/’”/g" | sed 's/``/“/g' | sed "s/''/”/g" | sed 's/`/‘/g' | sed "s/'/’/g" | sed 's/\\\"//g' | sed 's/\\~n/ñ/g' | sed 's/\~/ /g' | sed 's/\\ / /g' | sed 's/\\-//g' | sed 's/\\c{c}/ç/g' | sed 's/\\\///g' | sed 's/---/—/g' | sed 's/--/–/g' | awk -f tex-format.awk > $1.txt }
逻辑说明
- 栈结构:用
stack数组和stack_ptr指针模拟栈,遇到TeX格式命令时压入栈,遇到}时弹出栈顶元素,根据弹出的命令输出对应的Markdown闭合标记。 - 命令匹配:用AWK的
match函数检测开头的{\it、{\bf、{\sc命令,匹配成功后替换成对应的Markdown标记并压栈。 - 字符遍历:逐字符处理输入内容,确保每个字符都被正确处理,要么替换要么直接输出。
内容的提问来源于stack exchange,提问作者marcelgoh
相关产品推荐
相关产品推荐

