我需要检查第300个字符是否为{
,如果是,则需要将其替换为0,并在{之前考虑10位数时设为负十进制数。例如:如果输入为111123456789 {,则输出为11-112345678.90。
我的样本输入是:
H009704COV2009084 PHD0000001H009700204COV2009084 PROD2015122016010418371304COVH009704COV2009084 PTR0000001H0097002C00000000140000000043610000003408092A0000000068061C0000000000000{0000002939340H0000000537585H0000003476926F0000001218378G0000000040292E0000000016497{0000000000827E0000001880498{9000000320436J000000004391000000001606000000000030000000000128000000000006000000004227000000000000000000000000 00000140 0000000000000{0000000000773B0000000000000{000000000000
此处第300个字符为{
。因此,如果我将其替换为0并将其转换为负小数,则预期输出将为:
H009704COV2009084 PHD0000001H009700204COV2009084 PROD2015122016010418371304COVH009704COV2009084 PTR0000001H0097002C00000000140000000043610000003408092A0000000068061C0000000000000{0000002939340H0000000537585H0000003476926F0000001218378G0000000040292E0000000016497{0000000000827E000-000188049.809000000320436J000000004391000000001606000000000030000000000128000000000006000000004227000000000000000000000000 00000140 0000000000000{0000000000773B0000000000000{000000000000
我可以使用sed命令执行此操作:
sed -e 's/\ (.\ {1,255\ }\ )\ (.\ {1,34\ }\ )\ (.\ {1,9\ }\ )\ ([^{]*\ ){/\1\2+\3.\40/'
但是当输入文件有大量记录(~80000)时,性能很差。任何人都可以告诉我如何将上述sed命令转换为perl以获得相同的功能吗?
答案 0 :(得分:3)
在Perl中使用substr
函数。它通过偏移量,位置,长度在另一个内部找到一个字符串。它可以选择用另一个参数替换它。它返回此子字符串,找到并可能被替换。见substr documentation。这与此问题完全一致。
所需的转换有点复杂,因此它将涉及substr
的3次使用,并进行一些计数。 -
需要在左边10个位置插入,在左边两个位置插入小数点/逗号。最后,{
本身会被替换。请注意,对于第一个字符,位置计数从0开始。
要查看其工作原理,请使用注释中的示例,即
111123456789{ --> 11-112345678.90
在这种情况下,{
位于第12位。
echo "111123456789{" | perl -pne
'$x = substr($_, 2, 9); substr($_, 2, 9, "-$x."); substr($_, 14, 1, "0")'
必须在终端的单行输入;为了便于阅读,它在这里分为两行。上面的$_
是Perl的'默认'变量,它携带当前正在处理的内容,所以这里是字符串。这将按指定打印11-112345678.90
。
第一个命令在需要输入-
和.
的位置之间提取字符串,该位置从位置12左侧的10个位置开始(因此,在2处),长度为9然后将该子字符串写回那里,现在用-
和.
填充。最后,{
替换为0
。
更新 - subtstr
虽然上面允许更一般的转换,但是对于插入字符的确切任务,可以通过使用-
长度来简单地在给定位置添加.
和0
。 {
的替换如上所述。
perl -pne 'substr($_, 2, 0, "-"); substr($_, 12, 0, "."); substr($_, 14, 1, "0")'
这种方式$_
每次都会更改,最后由-p
开关提供打印(请参阅结束)。由于第一次插入会添加一个字符,因此第二次插入需要在字符串下方的一个位置发生。
请注意,这不是更有效。虽然它避免了创建新字符串$x
,但它会在一段时间后更改字符串。重写字符串的任何部分,除了确切的字符替换外,意味着至少要保留其余的字符串,然后将其复制回来。对于更长的字符串,这更昂贵,并且这种方法可能效率较低。但是,除非运行许多此类操作或基准测试,否则这不会是明显的。
要将此应用于实际问题,我们有299而不是12
perl -pne
'$x = substr($_, 289, 9); substr($_, 289, 9, "-$x."); substr($_, 301, 1, "0")'
input_file.txt
上面的第二个例子也可以使用,并有适当调整的数字。
开关和特殊变量:
-e
表示'...'
内部的内容将由Perl作为程序执行
-n
在输入行上循环(您可以使用许多此类行提供此文件)
-p
打印$_
(我们不需要说print
)
$_
有当前的输入行。
这也可以使用正则表达式完成。请参阅Perl Dog的答案,并在其下方找到更有效的评论。
答案 1 :(得分:1)
我理解Q和你的输入行,比如$line
,这个模式给了我你想要的结果:
$line =~ s/^(.{289}) # start and then 289 arbitrary chars -> $1
(\d{9}) # 9 digits -> $2
(\d) # another 10th digit -> $3
\{ # literal '{' at pos. 300
/${1}-${2}.${3}0/x;
然后替换是前289个字符,一个减号,接下来的9个数字,一个点,第10个数字,一个0(零)(其余的东西保持不变)。