Perl中更好的正则表达式解决方案?

Dre*_*ush 2 regex perl

这是我的问题:

我有五列的文本文件.最后一个总是有一个数字.反斜杠在前三个是非法的.空格可能会显示在第一列中.我删除了第一列中最后一个@之后的所有内容.列由空格分隔.我可以将列宽设置为我想要的任何值,让我对列之间的间距进行一些控制.

所以,我可能有这样的事情:

D Smith     Application     Database     Read     2
Run Code Online (Sandbox Code Playgroud)

我有代码将其转换为:

grant read on database 'Application'.'Database' to 'D Smith';
Run Code Online (Sandbox Code Playgroud)

这是我创建的正则表达式代码,用于分隔每个字段,避免混淆第一个字段中的任何空格与分隔间距.

while (<>) {
    s/^ //m;
    if (/^([^\\]+?)( {80,})/) {
        my $atindex = rindex($1,"@",);
        my $username = substr($1,0,$atindex);
        if ($atindex != -1) {
            s/^([^\\]+?)( {80,})/$username  $2/m;
            s/ {2,}/ \\ \\ /g;
            s/\\ \d$//gm;
            s/ \\ $//gm;
        }
    }
Run Code Online (Sandbox Code Playgroud)

这样做是\\ \\在字段之间做分隔符.然后我使用此代码进行转换:

if (/([^\\]+) \\ \\ ([^\\]+) \\ \\ ([^\\]+) \\ \\ ([^\\]+)\n/) {
    if ($4 eq "any") {
        my $execany = "execute any";
        print "grant $execany on database '$2'.'$3' to user '$1';\n";
    } else {
        print "grant $4 on database '$2'.'$3' to user '$1';\n";
    }
Run Code Online (Sandbox Code Playgroud)

我这样做是因为我无法找到一种方法来辨别第一个字段中可能出现的空格中的字段之间的空格.有没有更好的办法?这工作得足够快,但并不优雅.

Dav*_* W. 5

列是否恒定宽度?如果是这样,跳过正则表达式,只需使用substr:

数据格式

D Smith     Application     Database     Read     2
012345678901234567890123456789012345678901234567890
Run Code Online (Sandbox Code Playgroud)

程序

use strict;
use warnings;
use feature qw(say);

while ( my $line = <> ) {
    chomp $line;
    ( my $user = substr( $line, 0, 10 )) =~ s/\s*$//;
    ( my $file = substr( $line, 12, 15 )) =~ s/\s*$//;
    ( my $db   = substr( $line, 28, 12 )) =~ s/\s*$//;
    ( my $op   = substr( $line, 41, 9 )) =~ s/\s*$//;
    ( my $num  = substr ( $line, 50 )) =~ s/\s*$//;
    say qq(User = "$user", File = "$file", DB = "$db", OP = "$op", NUM = "$num");
}
Run Code Online (Sandbox Code Playgroud)

s/\s*$//;修剪字符串去除空白的右侧.

如果您不想使用所有这些子字符串,并且只有第一个字段可能包含空格,那么您可以使用substr拆分第一个字段,并拆分其余字段:

while ( my $line = <> ) {
    chomp $line;
    ( my $user = substr( $line, 0, 10 ) ) =~ s/\s*$//;
    my ( $file, $db, $op, $num ) = split /\s+/, substr( $line, 12 );
    ....
}
Run Code Online (Sandbox Code Playgroud)

另一种方案

列是否恒定宽度?......很好的解决方案 unpack也可以使用恒定宽度. - Kenosis

我们用unpack打包!

while ( my $line = <> ) {
    chomp $line;
    my ( $user, $file, $db, $op, $num ) = unpack ("A12A16A13A9A*", $line);
    say qq(User = "$user", File = "$file", DB = "$db", OP = "$op", NUM = "$num");
}
Run Code Online (Sandbox Code Playgroud)

是的,这很容易理解.至少我没有像我一样修剪我的琴弦substr.请参阅pack/unpack教程.