这是我的问题:
我有五列的文本文件。最后一个总是有一个数字。前三个反斜杠是非法的。第一栏中可能会出现空格。我删除第一列中最后一个@之后的所有内容。列由空格分隔。我可以将列宽度设置为几乎任何我想要的值,从而可以控制列之间的间距。
所以,我可能会有这样的事情:
D Smith Application Database Read 2
我有将其转换为以下代码:
grant read on database 'Application'.'Database' to 'D Smith';
这是我创建的Regex代码,用于分隔每个字段并避免将第一个字段中的任何空格与分隔间隔混淆。
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;
}
}
这是使
\\ \\
成为字段之间的分隔符。然后,我将以下代码用于转换: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";
}
我这样做是因为我无法找出一种方法来区分字段之间的空间和第一个字段中可能出现的空间。有没有更好的办法?这足够快地工作了,但是并不优雅。
最佳答案
正如我在对问题的评论中所描述的那样,只要您可以确保两个简单的假设都是有效的,就无需进行很多复杂的繁琐的正则表达式。这些假设是:
(如果不能保证由两个或多个空格组成的分隔符的那些假设,也许可以为三个或三个以上,四个或四个以上的分隔符&c。最好用可以确定的东西来分隔列永远不会出现任何价值,但如果没有这些价值,您可能希望做到最好。
给定这些假设,您可以在两个或多个空格的子字符串上对字符串进行
split()
,如下所示:while (<>) {
$_ =~ s@^\s+@@;
my @fields = split(/\s{2,}/, $_);
# print your commands, interpolating values from @fields
}
或者,更简单易读的是,您可以执行以下操作:
while (my $line = <STDIN>) {
# the same leading-space cleanup and split...
$line =~ s@^\s+@@;
my @fields = split(/\s{2,}/, $line);
# ...and then we assign values to a hash with meaningful keys...
my %values = ('user' => $fields[0],
'application' => $fields[1],
'database' => $fields[2],
'permission' => (lc($fields[3]) eq 'any'
? 'execany'
: $fields[3]));
# ...so that our interpolation and printing becomes much more
# readable.
print "grant $values{'permission'}"
. " on database '$values{'application'}'.'$values{'database'}"
. " to user '$values{'user'}';"
. "\n";
};
您还可以添加一些有效性检查,即确保给定行中期望的所有值都存在并且正确设置格式,并发出一些有用的提示,或者如果没有,则直接发送
die()
。