在多个文本文件中查找并替换数字,原始数字是否被修改?

在多个文本文件中查找并替换数字,原始数字是否被修改?

我需要找到所有字符串“5dp”,并将其替换为“(5*0.83)dp”,四舍五入为整数。数字 5 可以是任何数字,并且括号中的表达式实际上会被执行。

例如:31dp应该变成25dp

我需要递归搜索目录和子目录中的所有文件。有什么帮助吗?

答案1

使用find+ Perl:

find . -type f -exec \
perl -i -e 'use POSIX;' -pe 's/([0-9]*)dp/floor($1*.83).dp/ge' {} +

find命令:

  • .:在当前工作目录层次结构中搜索;
  • -type f:仅搜索文件;
  • -exec [...] {} +:执行以下命令,将搜索结果作为参数列表输入;

Perl 命令:

  • -i:指定<>构造处理的文件将在现场进行编辑;
  • -p: 导致 Perl 假设程序周围有以下循环,这使得它像sed:一样迭代文件名参数while (<>) {...} continue {print or die "-p destination: $!\n";}
  • -e:用于输入一行程序;Perl 不会在参数列表中寻找文件名;

Perl 命令 #1 分解:

  • use POSIX;:导入POSIX功能所需的模块POSIX::floor

Perl 命令 #2 分解:

  • s:断言执行替换
  • /:停止命令/启动模式
  • (:开始捕获组
  • [0-9]*:匹配任意数字
  • ):停止捕获组
  • dp:匹配一个dp字符串
  • /:停止模式/开始替换字符串
  • floor($1*.83).dpfloor($1*.83):用(其中$1是捕获组)的结果替换 Perl 表达式,后跟一个dp字符串
  • /:停止替换字符串/启动选项
  • g:断言全局执行替换
  • e:断言将替换字符串作为 Perl 命令执行

示例输出:

ubuntu@ubuntu:~/tmp$ tree
.
└── 1
    ├── 2
    │   ├── 3
    │   │   └── infile
    │   └── infile
    └── infile

3 directories, 3 files
ubuntu@ubuntu:~/tmp$ find . -type f -exec bash -c 'echo -e "{}:\n\n$(cat {})\n"' \;
./1/infile:

1dp 2dp 3dp 4dp 5dp
6dp 7dp 8dp 9dp 10dp
11dp 12dp 13dp 14dp 15dp

./1/2/infile:

1dp 2dp 3dp 4dp 5dp
6dp 7dp 8dp 9dp 10dp
11dp 12dp 13dp 14dp 15dp

./1/2/3/infile:

1dp 2dp 3dp 4dp 5dp
6dp 7dp 8dp 9dp 10dp
11dp 12dp 13dp 14dp 15dp

ubuntu@ubuntu:~/tmp$ find . -type f -exec perl -i -e 'use POSIX;' -pe 's/([0-9]*)dp/floor($1*.83).dp/ge' {} +
ubuntu@ubuntu:~/tmp$ find . -type f -exec bash -c 'echo -e "{}:\n\n$(cat {})\n"' \;
./1/infile:

0dp 1dp 2dp 3dp 4dp
4dp 5dp 6dp 7dp 8dp
9dp 9dp 10dp 11dp 12dp

./1/2/infile:

0dp 1dp 2dp 3dp 4dp
4dp 5dp 6dp 7dp 8dp
9dp 9dp 10dp 11dp 12dp

./1/2/3/infile:

0dp 1dp 2dp 3dp 4dp
4dp 5dp 6dp 7dp 8dp
9dp 9dp 10dp 11dp 12dp

答案2

更加详细的是下面的python脚本:

#!/usr/bin/env python3
import os
import sys

directory = sys.argv[1]

for root, dirs, files in os.walk(directory):
    for file in files:
        subject = root+"/"+file
        text = open(subject).read().split(" ")
        for i, s in enumerate(text):
            if s.endswith("dp"):
                try:
                    n = str(int(float(s.replace("dp", ""))*0.83))+"dp"; text[i] = n
                except ValueError:
                    pass
        open(subject, "wt").write((" ").join(text))

如何使用它

  • 将脚本复制到一个空文件中,另存为replace_numbers.py
  • 通过命令运行:

    python3 /path/to/replace_numbers.py <directory>
    

一个例子

a monkey eats 234dp bananas, while 2657dp would be too much. 234 is more the 12.

变成:

a monkey eats 194dp bananas, while 2205dp would be too much. 234 is more the 12.

解释:

  • 该脚本打开目录中的所有文件(逐个),读取它们并将其拆分为字符串。
  • 如果“dp” 在字符串中,它将数字与“dp”分开,(尝试)将其乘以0.83。然后对浮点数进行四舍五入(使用int(<float>))。如果从“dp”中剥离的字符串似乎不仅仅是一个数字,则跳过特定字符串的该过程(给出ValueError
  • 一旦传递了所有出现的“dp”,替换数字后的文本将再次写入文件,替换原始文本。

答案3

FWIW,这里有一个使用 bash oneliners 的解决方案:

(在我读到 OP 想要整数之前就已经准备好了,因此使用 bc 进行浮点运算。)

find . -type f|while read f;do cat "$f"|while read a;do b=`echo "$a"|sed 's/.*\([0-9]\+\)dp.*/\1*0.83/'|bc`;echo "$a"|sed s/"[0-9]\+dp"/"$b"dp/;done;done

...并向下舍入:

find . -type f|while read f;do cat "$f"|while read a;do b=`echo "$a"|sed 's/.*\([0-9]\+\)dp.*/\1*0.83/'|bc`;b=${b%.*};echo "$a"|sed s/"[0-9]\+dp"/"$b"dp/;done;done

相关内容