Chinaunix首页 | 论坛 | 博客
  • 博客访问: 26930
  • 博文数量: 13
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 130
  • 用 户 组: 普通用户
  • 注册时间: 2014-01-05 16:13
文章分类
文章存档

2016年(1)

2014年(12)

我的朋友

分类: PERL

2014-01-20 11:34:51

1.11.1 问题描述

希望实现对制表符和相应数量空格的相互转换,即当文件有许多连续的空格时,把空格转换成制表符可以减小文件的大小。有的设备不能识别制表符或者输出的制表符不是期望的位置,这个时候需要把制表符转换为空格。

1.11.2 解决方案

可以通过两种方式实现,一种是看起来有点怪怪的替换方式:

while ($string =~ s/\t+/' ' x (length($&) * 8 - length($`) % 8)/e) {

    # spin in empty loop until substitution finally fails

}

或者使用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;

}

为了避免使用变量$`,可以使用稍微复杂的另外一种替换,使用数值变量进行显式的捕捉,下模的例子将制表符扩展为四个空格

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

另外一种方法是通过使用数组@+@-,使用偏移量来将制表符扩展为四个空格

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


回顾上面几个while的循环,是否你想知道为什么这个循环不能用简单的s///g代替呢?这是因为我们每次都要从行的开始重新计算长度,而不是从上次的匹配成功开始。

1 while CONDITION“的用法和”while (CONDITION){}”的用法是一样的,只是较短而已。这种用法起源于之前的Perl第一个循环比第二个循环运行的速度快很多的时候,当然限制第二个循环的速度也相当快了,这只是一个习惯的用法。

    标准的库模块Rext::Tabs提供了转换函数实现两种符号的相互转换。用$tabstop变量控制每个制表符空格的数量并且不会降低程序的性能,因为它使用的是数值变量$1,$2而不是$&,$`.

use Text::Tabs;

$tabstop = 4;

while (<>) { print expand($_) }

我们也可以使用 Text::Tabs 但是不扩制表符空格的数量,下面的例子用的是$tabstop的默认值8.

use Text::Tabs;

while (<>) { print unexpand($_) }

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