在比赛前替换第一个角色

时间:2013-07-07 12:06:55

标签: regex perl csv substitution

对于每一行,我需要在字母数字符号的第一个匹配之前添加一个分号,但仅在第一次出现分号后添加字母数字符号。

示例:

输入:

00000001;Root;;
00000002;  Documents;;
00000003;    oracle-advanced_plsql.zip;file;
00000004;  Public;;
00000005;  backup;;
00000006;    20110323-JM-F.7z.001;file;
00000007;    20110426-JM-F.7z.001;file;
00000008;    20110603-JM-F.7z.001;file;
00000009;    20110701-JM-F-via-summer_school;;
00000010;      20110701-JM-F-via-summer_school.7z.001;file;

期望的输出:

00000001;;Root;;
00000002;  ;Documents;;
00000003;    ;oracle-advanced_plsql.zip;file;
00000004;  ;Public;;
00000005;  ;backup;;
00000006;    ;20110323-JM-F.7z.001;file;
00000007;    ;20110426-JM-F.7z.001;file;
00000008;    ;20110603-JM-F.7z.001;file;
00000009;    ;20110701-JM-F-via-summer_school;;
00000010;      ;20110701-JM-F-via-summer_school.7z.001;file;

有人可以帮助我为此创建Perl正则表达式吗?我需要一个程序,而不是一个oneliner。

3 个答案:

答案 0 :(得分:3)

这是在第一个分号和空格之后但在第一个非空格之前插入分号的方法。

s/;\s*\K(?=\S)/;/

如果您觉得有必要,可以使用\w代替\S,但我觉得这个输入是不必要的规范。

\K(keep)转义类似于lookbehind断言,因为它不会删除匹配的内容。前瞻断言也是如此,所以所有这些替换都是在指定位置插入一个分号。

答案 1 :(得分:1)

首先,这是一个似乎符合您要求的程序:

#/usr/bin/perl -w
while(<>) {                                                           
  s/^(.*?;.*?)(\w)/$1;$2/;                                            
  print $_;                                                           
}                                                                     

将其存储在'program.pl'文件中,使用'chmod u + x program.pl'使其可执行,并在输入数据上运行,如下所示:

program.pl input-data.txt

以下是正则表达式的解释:

s/        # start search-and-replace regexp
  ^       # start at the beginning of this line
  (       # save the matched characters until ')' in $1
    .*?;  # go forward until finding the first semicolon
    .*?   # go forward until finding... (to be continued below)
  )
  (       # save the matched characters until ')' in $2
    \w    # ... the next alphanumeric character.
  )
/         # continue with the replace part
  $1;$2   # write all characters found above, but insert a ; before $2
/         # finish the search-and-replace regexp.

根据您的示例输入,我将使用更具体的正则表达式:

s/^(\d*; *)(\w)/$1;$2/;

此表达式从行的开头开始,跳过数字(\ d *),后跟第一个分号和空格。在下面的单词字符之前,它会插入一个分号。

尽量满足您的需求!

答案 2 :(得分:0)

首先感谢您的真正好的答案!

实际上我的代码片段如下所示:

 our $seperator=";" # at the beginning of the file
 #...
 sub insert {
    my ( $seperator, $line, @all_lines, $count, @all_out );
    $count     = 0;
    @all_lines = read_file($filename);

    foreach $line (@all_lines) {
        $count = sprintf( "%08d", $count );
        chomp $line;
        $line =~ s/\:/$seperator/;                          # works
        $line =~ s/\ file/file/;                            # works

        #$line=~s/;\s*\K(?=\S)/;/;                          # doesn't work
        $line =~ s/^(.*?$seperator.*?)(\w)/$1$seperator$2/; # doesn't work
        say $count . $seperator . $line . $seperator; 

        $count++; # btw, is there maybe a hidden index variable in a foreach-loop I could us instead of a new variable??
        push( @all_out, $count . $seperator . $line . $seperator . "\n" );
    }

    write_file( $csvfile, @all_out ); # using File::Slurp
}

为了得到我给你的输入,我已经做了一些小的替换,正如你在foreach循环开头看到的那样。

我很好奇,为什么TLP和Yaakov提出的正则表达式在我的代码中不起作用。一般来说,他们的工作,但只有在Yaakov给出的例子中写的时候:

while(<>) {                                                           
  s/^(.*?;.*?)(\w)/$1;$2/;                                            
  print $_;                                                           
}