需要一个简单的预处理器来处理文本文件

0 投票
5 回答
793 浏览
提问于 2025-04-18 14:49

我需要把一个文本文件里的简单表达式去掉,然后保存到一个新文件里。用什么表达式语言都可以。举个例子:

输入文件:

days = 12
times_per_day = 10
extra = 2
The quick brown fox jumped $days * ($times_per_day + $extra) times over the lazy dog

输出文件:

The quick brown fox jumped 144 times over the lazy dog

这个程序需要在Windows上运行。我考虑过的一些方法是:使用C语言的预处理器(不过我觉得它可能无法静态地处理所有表达式?),或者用perl/python/awk等语言来写我的输入文件(但这样可能不太好读)。

我希望在3到4个小时内解决这个问题,所以我不想写一个完整的解析器。

5 个回答

0

如果你把上面那些表达式的评估和替换分开做,会简单很多。在一句话中找到一个要评估的表达式其实挺麻烦的,不过在=右边做这个就简单多了。所以像下面这样的操作,几分钟就能搞定,而且仍然可以用来构建一个非常复杂的语言。

data = '''days = 12
times_per_day = 10
extra = 2
total = $days * ($times_per_day + $extra)
The quick brown fox jumped $total times over the lazy dog
This is a new line that does nothing
The next line will reassign the variable total
total = $total + 1
Now the value of total is $total
'''.split('\n')

variables = {}

def replaceVariables(l):
    for k in variables: l = l.replace(k, variables[k])
    return l

def evalExpression(l): return str( eval( replaceVariables(l) )  )

for l in data:

    # if its a variable assignment, create a new variable 
    # this is also going to replace an old variable. 
    if '=' in l: 
        v, d = map(lambda m: m.strip(), l.split('='))
        variables['$' + v] = evalExpression(d) 
        continue

    # Otherwise just replace variables
    print replaceVariables(l)

对于上面的内容,结果是:

In [13]: run test18
The quick brown fox jumped 144 times over the lazy dog
This is a new line that does nothing
The next line will reassign the variable total
Now the value of total is 145
1

下面是用PHP写的代码示例:

<?
$days = 12;
$times_per_day = 10;
$extra = 2;
?>

The quick brown fox jumped <? echo $days * ($times_per_day + $extra); ?> times over the lazy dog

在这个输入下,PHP会产生以下结果:

The quick brown fox jumped 144 times over the lazy dog

我唯一不喜欢的就是需要使用echo这个命令(还有在Windows上安装PHP的难度)。

3

在Python中,我会使用一个模板引擎。比如说Jinja2。代码如下:

from jinja2 import Environment, FileSystemLoader, Template


def main():
    environment = Environment(loader=FileSystemLoader('.'), trim_blocks=True)
    template = environment.get_template('test.tpl')
    print template.render()


if __name__ == '__main__':
    main()

模板文件 test.tpl

{% set days = 12 %}
{% set times_per_day = 10 %}
{% set extra = 2 %}
The quick brown fox jumped {{days * (times_per_day + extra)}} times over the lazy dog.

输出结果:

The quick brown fox jumped 144 times over the lazy dog.
4

如果你打算使用 AWK,那为什么 GNU Bash 不合适呢?可以这样理解:

#!/bin/bash
days=12
times_per_day=10
extra=2
cat << EOF
The quick brown fox jumped $((days * (times_per_day + extra))) times over the lazy dog
EOF

希望这个例子能让你看得懂。

如果你出于某种原因想要不使用 cat(这是一个外部工具),那也没问题:

while read; do printf '%s\n' "$REPLY"; done << EOF
The quick brown fox jumped $((days * (times_per_day + extra))) times over the lazy dog
EOF
3

每次使用 eval 的时候,几乎可以说是在搞一些小聪明。

不过,下面这个 perl 的“一行代码”在这个特定的情况下确实能完成任务:

perl -ne '!eof() ? eval "\$$_" : s/(?<!\S)(?=[[:punct:]\d]*\$)((?:\$\w+|[[:punct:]\d]+|\s+)+)(?!\S)/\@{[$1]}/g && print eval qq{"$_"};' fox.txt

输出结果:

The quick brown fox jumped 144 times over the lazy dog

解释:

开关选项

  • -n: 为输入文件的每一行创建一个 while(<>){...} 循环。
  • -e: 告诉 perl 在命令行上执行代码。

代码说明

  • !eof(): 根据是否到达文件末尾来选择性处理。
  • eval "\$$_": 将一行像 foo = 3 的内容转化为 $foo = 3
  • s/(?<!\S)(?=[[:punct:]\d]*\$)((?:\$\w+|[[:punct:]\d]+|\s+)+)(?!\S)/\@{[$1]}/g

    把像 string $foo * $bar end 的文本转化为 string @{[$foo * $bar]} end

  • print eval qq{"$_"};: 打印最后一行的计算结果。

撰写回答