Chinaunix首页 | 论坛 | 博客
  • 博客访问: 485254
  • 博文数量: 142
  • 博客积分: 4126
  • 博客等级: 上校
  • 技术积分: 1545
  • 用 户 组: 普通用户
  • 注册时间: 2008-02-22 10:03
文章分类

全部博文(142)

文章存档

2011年(8)

2010年(7)

2009年(64)

2008年(63)

我的朋友

分类:

2008-11-25 16:42:03

1.11.1. 提出问题

你想将字符串中的制表符转换为合适数目的空格,或者是反过来。当文件中有许多连续空格的时候,将它们转换为制表符可以使文件变小。将制表符转换为空格有时也是必要的:当你的输出设备无法处理制表符,或者和你想要的位置效果不一样的时候。

1.11.2. 解决方案

你可以使用一个看起来很怪异的表达式替换:

 

while ($string =~ s/\t+/' ' x (length($&) * 8 - length($`) % 8)/e) {
    
# 如果匹配失败则是空的循环
}

或者使用标准模块 Text::Tabs:

use Text::Tabs;
@expanded_lines = expand(@lines_with_tabs);
@tabulated_lines = unexpand(@lines_without_tabs);

1.11.3. 讨论

假定制表符每 N 格放一个(默认情况下 N 是8),那么将它们换成空格很容易。标准的教科书式方法并不使用 Text::Tabs 模块,不过有点难于理解。而且它使用 $` 变量,每次在匹配中使用它都会降低运行速度。在第六章特殊变量中对此有所讲述。你可以用如下算法来将输入中的指标符换成 8 格空格:

 

while (<>) {
    1 while s/\t+/' ' x (length($&) * 8 - length($`) % 8)/e;
    print;
}

要避免使用 $`,你可以一个稍微复杂一些的方法,使用数字变量来显式捕捉匹配内容。以下代码将制表符转换为 4 格空格:

 

1 while s/^(.*?)(\t+)/$1 . ' ' x (length($2) * 4 - length($1) % 4)/e;

# 另一个方法是使用 @+@- 的偏移量。以下代码也将制表符换成 4 格空格:

1 while s/\t+/' ' x (($+[0] - $-[0]) * 4 - $-[0] % 4)/e;


你会想为什么这个1 while 循环不直接写成简单的 s///g 的形式,这是因为你需要每次重新计算从行起始的偏移量,而不是从上次匹配的地方开始。

1 while CONDITION 和 while (CONDITION) { } 是等价的,就是更短些。它最早开始出现的时候,当时的 perl 运行第一个比第二个快得多,而到现在,两个都差不多快了。不过前者很方便,而且有些人已经用成了习惯。

标准模块 Text::Tabs 为两种转换都提供了相应的函数,它有一个 $tebstop 变量控制一个制表符对应几个空格,而且它没有引入效率上的问题,因为它使用的是 $1 和 $2,而不是 $& 和$`。

use Text::Tabs;
$tabstop = 4;
while (<>) { print expand($_) }

也可以用 Text::Tabs 来“扩展”制表符。这个例子使用了默认的 8 做为 $tabstop 的值。

 

use Text::Tabs;
while (<>) { print unexpand($_) }

1.11.4. 参见

Text::Tabs 模块的文档。 perlre(1) 和 perlop(1) 中的 s/// 操作符。 @+ 和 @-(@LAST_MATCH_START and @LAST_MATCH_END)在 Programming Perl 的第二十八章。Programming Perl 的第五章,“When a global substitution just isn't global enough”。

1.11.5 试验程序
 

#!/usr/bin/perl

##########################################方法一

#$/=undef;

while(<DATA>){
while ( s/\t+/' ' x (length($&) * 8 - length($`) % 8)/e) { }
print ;
}
##########################################方法二

#use Text::Tabs;

#@test=expand();

#print @test;


__DATA__
malshegsldkj
asd f
ldk f ja
asd f asdf asdsdf
aa bb
cc dd
ee ff


阅读(390) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~