1

** 我有一个标有“ * *”的后续问题**

我被要求编写 Perl 代码,用每次{替换{function(<counter>),每次替换时,计数器应该变大 1。例如,第一次替换{will be {function(0) ,第二次替换{will be{function(1)等。假设在文件夹中的每个*.c*.h文件中进行替换包括子文件夹。

我写了这段代码:

#!/usr/bin/perl
use Tie::File;
use File::Find;
$counter = 0;
$flag = 1;

@directories_to_search = 'd:\testing perl';
@newString = '{ function('.$counter.')';
$refChar = "{";
finddepth(\&fileMode, @directories_to_search);


sub fileMode 
{
 my @files = <*[ch]>;   # get all files ending in .c or .h
 foreach $file (@files) # go through all the .c and .h flies in the directory  
{
    if (-f $file)  # check if it is a file or dir
    {
    my @lines;
# copy each line from the text file to the string @lines and add a function call after every     '{' '
    tie @lines, 'Tie::File', $file or die "Can't read file: $!\n";
    foreach ( @lines )
    {
        if (s/{/@newString/g)
        {
            $counter++;
            @newString = '{function('.$counter.')';
        }
        untie @lines; # free @lines
    }
    }
}   
}

代码搜索目录d:\testing Perl并进行替换,但 {function(<number>)我没有得到 {function(number1) function(number3) function(number5) function(number7)例如我得到的第一个替换 {function(0) function(2) function(4) function(6),我想得到{function(0)

我真的不知道我的代码有什么问题。

awk 解决方案或任何其他 Perl 解决方案也会很棒!


* 我有一个后续问题。现在我希望我的 perl 程序在所有文件中执行相同的替换,除了同一行中有“{”
和“}”的行。所以我以这种方式修改了代码。

#!/usr/bin/perl

use strict;
use warnings;
use Tie::File;
use File::Find;

my $dir = "C:/test dir";   


# fill up our argument list with file names:
find(sub { if (-f && /\.[hc]$/) { push @ARGV, $File::Find::name } }, $dir);

$^I = ".bak";   # supply backup string to enable in-place edit 

my $counter = 0; 

# now process our files
#foreach $filename (@ARGV) 
while (<>) 
{
    my @lines;
    # copy each line from the text file to the string @lines and add a function call after every '{' '
    tie @lines, 'Tie::File', $ARGV or die "Can't read file: $!\n";
    #$_='{function(' . $counter++ . ')';

    foreach  (@lines) 
    {   
        if   (!( index (@lines,'}')!= -1 )) # if there is a '}' in the same line don't add the     macro
            {
                s/{/'{function(' . $counter++ . ')'/ge;
                print;
            }

    }
    untie @lines; # free @lines
}    

我试图做的是遍历我在我的目录和子目录中找到的@ARGV 中的所有文件,对于每个 *.c 或 *.h 文件,我想逐行检查并检查此行是否包含'{ '。如果是,程序将不会检查是否有'{'并且不会进行替换,如果没有,程序将用'{function();'替换'{'

不幸的是,这段代码不起作用。我很惭愧地说,我试图让它工作一整天,但仍然没有成功。我真的很感激一些帮助。

谢谢你!!

4

4 回答 4

3

这是将查找方法与就地编辑相结合的简单问题。您可以使用Tie::File,但它实际上是相同的最终结果。此外,不用说,在进行此类编辑时,您应该始终保留原始文件的备份,因为更改是不可逆的。

因此,如果您不需要递归,您的任务在 Unix/Linux 风格中非常简单:

perl -pi -we 's/{/"{ function(" . $i++ . ")"/ge' *.h *.c

当然,由于您似乎使用的是 Windows,cmdshell 不会全局化我们的参数,因此我们需要手动执行此操作。我们需要改变引号。而且,我们需要为-i(就地编辑)开关提供一个备份参数。

perl -pi.bak -we "BEGIN { @ARGV = map glob, @ARGV }; s/{/'{ function(' . $i++ . ')'/ge" *.h *.c

这几乎足以制作一个脚本。

如果你确实需要递归,你会使用File::Find. 请注意,此代码在功能上与上述代码几乎相同。

use strict;
use warnings;
use File::Find;

my $dir = "d:/testing perl";   # use forward slashes in paths

# fill up our argument list with file names:
find(sub { if (-f && /\.[hc]$/) { push @ARGV, $File::Find::name } }, $dir);

$^I = ".bak";   # supply backup string to enable in-place edit 

my $counter = 0; 

# now process our files
while (<>) {
    s/{/'{ function(' . $counter++ . ')'/ge;
    print;
}

不要被备份选项迷惑成错误的安全感:如果您连续两次运行此脚本,这些备份将被覆盖,因此请记住这一点。

于 2013-01-09T13:16:40.313 回答
2
$ perl -pi -e 's| (?<={) | q#function(# . ($i++) . q#)# |gex' *.c *.h
于 2013-01-09T13:08:18.847 回答
1

使用awk '/{/{gsub(/{/,"{function("i++")");print;next}{print}'和您的代码作为输入:

$ awk '/{/{gsub(/{/,"{function("i++")");print;next}{print}' file
sub fileMode 
{function(0)
 my @files = <*[ch]>;   # get all files ending in .c or .h
 foreach $file (@files) # go through all the .c and .h flies in the directory  
{function(1)
    if (-f $file)  # check if it is a file or dir
    {function(2)
    my @lines;
# copy each line from the text file to the string @lines and add a function call after every     '{function(3)' '
    tie @lines, 'Tie::File', $file or die "Can't read file: $!\n";
    foreach ( @lines )
    {function(4)
        if (s/{function(5)/@newString/g)
        {function(6)
            $counter++;
            @newString = '{function(7)function('.$counter.')';
        }
        untie @lines; # free @lines
    }
    }
}   
}

注意:内联嵌套的函数编号不会增加{

$ echo -e '{ { \n{\n-\n{' | awk '/{/{gsub(/{/,"{function("i++")");print;next}1'
{function(0) {function(0) 
{function(1)
-
{function(2)

解释:

/{/                               # For any lines that contain {
gsub( /{/ , "{function("i++")" )  # replace { with function(i++)
print;next # print the line where the replacement happened and skip to the next
print                             # print all the lines 
于 2013-01-09T12:51:27.077 回答
1

它可以在一行中完成,如下所示:

perl -pi -e 's/({)/"{function(".++$a.")"/ge;' your_file

我刚刚获取了一个示例输入文件并进行了测试。

> cat temp
line-1 {    {    {   {
line-2 {    {   {
line-3 {    {
line-4 {

现在执行:

> perl -pi -e 's/({)/"{function(".++$a.")"/ge;' temp
> cat temp
line-1 {function(1)    {function(2)    {function(3)   {function(4)
line-2 {function(5)    {function(6)   {function(7)
line-3 {function(8)    {function(9)
line-4 {function(10)
于 2013-01-09T13:21:02.807 回答