![在多个文本文件中查找并替换数字,原始数字是否被修改?](https://linux22.com/image/983885/%E5%9C%A8%E5%A4%9A%E4%B8%AA%E6%96%87%E6%9C%AC%E6%96%87%E4%BB%B6%E4%B8%AD%E6%9F%A5%E6%89%BE%E5%B9%B6%E6%9B%BF%E6%8D%A2%E6%95%B0%E5%AD%97%EF%BC%8C%E5%8E%9F%E5%A7%8B%E6%95%B0%E5%AD%97%E6%98%AF%E5%90%A6%E8%A2%AB%E4%BF%AE%E6%94%B9%EF%BC%9F.png)
我需要找到所有字符串“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).dp
floor($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