我有一个非常非常大的文本文件,我正在使用具有各种大小的缩进的行.那些可接受的行具有12个字符宽度的缩进,这些缩进是由制表符和空格的组合创建的.现在我想获得所有没有12个字符宽度的缩进的行,并且这些行具有从制表符和空格字符组合的0到11个字符宽度的缩进.
if $badLine !~~ m/ ^^ [\s ** 12 || \t \s ** 4 || \s \t \s ** 3 ] / { say $badLine; }
但问题是,当您使用文字处理器处理文本文件时,按Tab键可以为您提供0到8 space-char-width的任何位置以填补空白.什么是一种聪明的方法来获得所有那些没有12个字符宽度缩进的不可接受的行?
谢谢.
解决方法
宽度12
对于缩进宽度为12,假设制表位于0,8,16等位置:
for $input.lines { .say if not / ^ # start of line [" " ** 8 || " " ** 0..7 \t] # whitespace up to first tab stop [" " ** 4] # whitespace up to position 12 [\S | $] # non-space character or end of line /; }
说明:
>要从行的开头(位置0)到第一个制表位(位置8),我们需要匹配两种可能性:
> 8个空格.
> 0到7个空格,后跟1个选项卡. (标签直接跳到制表位,因此它会填充空格后剩余的宽度.)
>从制表位(位置8)到缩进目标(位置12)的唯一方法是4个空格. (标签会跳过目标到位置16的下一个标签位置.)
>锚定到行的开头,以及缩进后的任何内容都很重要,这样我们就不会意外地匹配较长缩进的部分内容.
任意宽度
压痕匹配可以分解为可以处理任意宽度的参数化named token:
my token indent ($width) { [" " ** 8 || " " ** 0..7 \t] ** {$width div 8} " " ** {$width % 8} } .say if not /^ <indent(12)> [\S | $]/ for $input.lines;
说明:
>使用与上面相同的表达式进入第一个制表位,但现在它会根据需要重复多次,以到达目标之前的最后一个制表位. ($width div共计8次,其中div
是整数除法运算符).
>无论最后一个制表位与目标之间的距离是什么,都必须填充空格. ($width%8个空格,其中%
是模运算符.)
任意位置和宽度
上例中的标记假定它在标签停止位置(例如行的开头)开始匹配.它可以进一步推广以匹配给定宽度的制表符和空格,无论您在哪个行中调用它:
my token indent ($width) { :my ($before-first-stop,$numer-of-stops,$after-last-stop); { $before-first-stop = min $width,8 - $/.from % 8; $numer-of-stops = ($width - $before-first-stop) div 8; $after-last-stop = ($width - $before-first-stop) % 8; } [" " ** {$before-first-stop} || " " ** {^$before-first-stop} \t] [" " ** 8 || " " ** 0..7 \t] ** {$numer-of-stops} " " ** {$after-last-stop} }
说明:
>与以前相同的原则,除了现在我们首先需要匹配尽可能多的空格以从字符串中的当前位置到其后面的第一个制表位.>字符串中的当前位置由$/.来自;其余的是简单的算术.>在令牌中声明并使用了一些词法变量(带有希望描述性的名称),以使代码更容易理解.