$ /是否有可能支持正则表达式?

时间:2013-10-03 12:18:28

标签: perl

引用perlvar

  

... $/的值是一个字符串,而不是一个正则表达式。 awk必须更好。 : - )

不难想到这样的功能会有用的情况 - 解析具有可变长度记录的文件是我经常遇到的一个经典用例。

到目前为止,我从未遇到过将整个文件加载到内存中并执行以下操作的问题:

my @records = split /my_regex/, <> ;

但由于显而易见的原因,这种技术不能用于可用内存不足的情况。实际上,很多时候不需要同时存储所有记录。

这让我回到$/

我觉得奇怪的是该语言没有为$/配置正则表达式支持。这是按设计完成的吗?是否根本无法实施?还有哪些其他变通方法可以被认为是缺乏优秀功能的最佳实践?

4 个答案:

答案 0 :(得分:8)

即使尝试也没有多大意义。很多时候,如果没有阅读结束,你将无法判断你是否到达了终点。在互动情况下这可能非常糟糕。

例如,假设您有以下程序:

local $/ = qr/\n|\r\n?/;  # Handle Windows, Unix and old MacOS line endings.
while (1) {
   print "Please enter a command: ";
   my $cmd = <>;
   $cmd =~ s{$/\z}{};
   process($cmd);
}

看起来非常简单,对吧?实际上,支持qr/\n|\r\n?/可能是此请求的首要原因。好吧,即使是那么简单的代码也存在严重缺陷。假设我使用MacOS行结尾(CR,^ M,\ r)

 $ processor
 Please enter a command: foo^M
 [hangs]

该程序挂起,因为它无法判断我是否给它一个MacOS行结尾(CR,^ M,\ r)或Windows行结尾(CRLF,^ M ^ J,\ r \ n)直到另一个字符输入。

我必须输入第二个命令来处理第一个命令,第三个命令来处理第二个命令,等等。这没有任何意义。

答案 1 :(得分:4)

我能看到的最大问题之一是支持一般的正则表达式记录分隔符 需要扫描文件的全部内容。

例如,假设您出于某种原因指定了/\n[^X]+\z/的分隔符。需要读取整个文件以检查每个换行符后是否有X个字符。

所以我可以想到三个选项:

  • 缓冲整个文件只是为了扫描记录分隔符

  • 在“分页”字符串上实现正则表达式,以便可以部分读取文件

  • 实现标准正则表达式的子集以用作记录分隔符

从实现的角度来看,这些都不是特别有吸引力的前景,我可以看到,如果可能,我会避免这样做,特别是因为Perl编码器通过使用{{1}可以使用第一个选项}。

答案 2 :(得分:3)

Perl正则表达式引擎的(回溯)实现从根本上与作为行尾的用法不兼容。这个问题的一部分是你不想在读取下一个字符时重新运行整个正则表达式。例如,取正则表达式

$/ = qr/ A \w*? B | XY/;

和数据流

f o o A 1 2 X Y B b a r

那么readline什么时候应该回来?如果我们进行增量匹配,我们可能会得到像

这样的东西
f o o A 1 2 X Y B b a r
      A\w\w\w\w B

#=> fooA12XYB

如果我们在每个位置重新运行整个正则表达式,我们得到

f o o A 1 2 X Y B b a r

      A *FAIL
      *FAIL

      A\w *FAIL
      *FAIL

      A\w\w *FAIL
      *FAIL

      A\w\w\w *FAIL
            X *FAIL

      A\w\w\w\w *FAIL
            X Y

#=> fooA12XY

换句话说,替换(优先级)使这种匹配变得复杂。如果正则表达式引擎没有回溯(但宁愿作为表解析器或状态机运行),则重新运行整个正则表达式或进行增量匹配之间没有区别。但是,可能的正则表达式引擎比Perl正则表达式更具表现力。

另一个问题是结束行

$/ = qr/ .+ /xs;

读取这样的“行”是否只返回下一个字符(因为正则表达式已在一个字符后满足),或整个文件(因为.*想要尽可能匹配)?或者是否应返回内部缓冲区的其余部分,无论它当前包含什么内容?

要使用正则表达式进行行结尾,必须解决这些含糊之处,并且必须施加其他限制(例如,只允许使用常规语言)。

答案 3 :(得分:0)

Perl6::Slurp看起来像是一种可行的工作方式:

  

您可以设置输入记录分隔符({irs =&gt; $ your_irs_here})   输入操作。分隔符可以指定为字符串或a   正则表达式。