假设我有像这样的倍数
我的输入行:
"stack overflow version {5} my new version"
"stack exchnage version {10} my new version"
"perl scripting version 5.14 my new version"
"segmentaion falult happen {5} if the memory is not freed"
" my college 30 new xxxx"
我想一次替换所有行中括号内的值。
我的方法:
use strict;
use warnings;
my $old_parameter='stack overfolw version';
my $new_parameter;
my $old_value={5};
my $new_value='20 ';
my $filename ='input.txt'
open my $fh, "<", $filename or die "Couldn't open input file: $!";
while ( <$fh> )
{
if (/$old_parameter/ and /$old_value/)
{
s/$old_value/$new_value/;
}
}
输出:
stack overflow version {20} my new version; #values change from 5 to 20
现在我已经对20的值进行了硬编码,但是我要找的是我将值(1..100)存储到某个数组中,我会根据我要替换的每一行选择值。
为此我需要匹配线然后我必须做替换。
那么最好的方法是什么?
答案 0 :(得分:1)
到目前为止,问题已经呈现出来了。我认为你想要更改文件中特定行的{ }
中的数字。发布的代码已经关闭,我将对基础知识进行评论并完成它。
由于我们现在找到{ }
内的数字,因此不需要硬编码$old_value
。为了确定所需的行,您需要匹配$old_parameter
,以便条件变为if (/$old_parameter/)
。随后对regex matching发表评论,仅与代码中使用的内容相关。请阅读文档和书籍了解更多信息。
考虑while (my $line = <$fh>)
。 diamond operator <>
通过$fh
从文件中读取一行,并将其分配给变量$line
。如果省略变量并只写while (<$fh>)
,那么该行将被分配给名为$_
的特殊变量。此变量通常用作Perl中的默认值。请参阅General Variables。
要检查模式是否在变量中,要“匹配”,我们说$var =~ m/$patt/
。这在标量上下文中返回true或false,而在 list context 中它返回匹配项。见Extracting Matches。模式最好放在$patt = qr(...)
变量中。我们的行位于$_
,因此我们需要$_ =~ m/$patt/
,其中m
可能会被省略。正则表达式还允许使用快捷方式,因为它在$_
上默认有效,我们可能会说/$patt/
。因此if (/.../)
。
现在考虑substitution。要查找模式并替换它,我们会说$var =~ s/$patt/$repl/
。这会更改$var
“就地”,这意味着在该语句$var
发生更改后。如果在$patt
中找不到$var
则没有任何反应。在$_
中我们的行,我们再次需要$_
而不是$var
,但相同的快捷方式有效,我们可以说s/$patt/$repl/
。
你的代码有这个 - 但它没有做任何事情。结果从未由程序给出。一种简单的方法是打印每一行,输出可以重定向到文件。或者将行写入文件。
现在需要正则表达式。你想要一个{ }
里面的数字。根据您显示的数据,它是该行中唯一的此类模式。然后这样做
s/ \{ \s* \d+ \s* \} /{$new_value}/x;
/x
允许我们使用空格来实现可读性。 (否则它们将在字符串中查找!)数字由\d
匹配,而+
表示所有相关的数字,但至少有一个。在a123b
123
匹配a12b3c
,12
匹配{
。 }
和\s*
被转义,因为它们在正则表达式中具有特殊含义。 {$new_value}
允许任意数量的空格,或者不允许任何空格。
正则表达式的替换方面表示要替换与{
匹配的所有内容。我们不必逃避}
,()
。如果您需要捕获(请记住)匹配的内容将模式置于s/ (\{ \s*) (\d+) (\s* \}) /$1$new_value$3/x;
之间。在这里你可以说
$1
并保留原始空格。第一次捕获存储在$2
中,第二次捕获存储在$new_value
中,等等。如果use warnings 'all';
use strict;
my $old_parameter = 'stack overflow version';
my $new_value = 20;
my $filename = 'input.txt';
open my $fh, "<", $filename or die "Can't open $filename: $!";
while ( <$fh> )
{
if (/$old_parameter/)
{
s/\{\s* (\d+) \s*\}/{$new_value}/x;
}
print;
}
在循环期间发生变化,您可以在替换之前计算它。
请参阅Schwern的答案以及ikegami的评论中提供的技巧。
然后我们只需打印该行。完整的程序
print;
$_
使用相同的默认值print $_;
,表示$old_parameter
。在条件之后,所有行都被打印,更改或不更改。其他一些错误已得到修复。一个有趣的是:您的roomEntry.put(num,new Entry(newRoom.code));
“堆叠在 folw 版本”(拼写错误),因此从不匹配该行
最后,请仔细阅读perlretut,或者更好的方法,通过正在使用的书籍或正在使用的教程中的正则表达式的精彩章节。
答案 1 :(得分:-2)
我想替换括号内的值而值不是 常数会因文件而异。
您正在寻找的是“角色类”或“角色集”。正则表达式可以匹配数字,字母等字符集。许多都是内置的,您可以指定自己的。
\d
匹配一个数字。\w
匹配数字或字母。[abc]
匹配字母a,b或c。[^abc]
匹配任何但字母a,b或c。有关详情,请参阅Perl Regex Tutorial on Using Character Classes。
通常这些匹配恰好是一个字符。有多种方式可以说明要匹配多少。
*
表示匹配0或更多。+
说一个或多个。?
说零或一。{3,}
表示匹配三个或更多。{3,5}
说三到五。它们会在您匹配的任何内容中结束,例如\d+
表示“匹配1位或更多位数”。
有关详情,请参阅Perl Regex Tutorial on Matching Repetitions。
将它们组合在一起,您可以/\{\d+\}/
或更清楚地m[ \{ \d+ \} ]x
表示大括号之间的一个或多个数字。必须对大括号进行转义,以免将它们与{3,5}
重复语法混淆。末尾的x
意味着忽略空格,因此可以使用空格来格式化正则表达式。 m[ ... ]
是另一种编写正则表达式以避免leaning toothpick syndrome的方法。
搜索和替换在左侧使用相同的语法,因此s[ \{ \d+ \} ][ the replacement ]x
。