7

引用perlvar

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

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

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

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

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

这让我回到了$/.

我觉得奇怪的是该语言没有为$/. 这是设计使然吗?是不是根本无法实施?在没有什么漂亮功能的情况下,还有哪些其他解决方法可以被视为最佳实践?

4

4 回答 4

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),直到输入另一个字符。

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

于 2013-10-03T13:36:45.567 回答
4

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

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

所以我能想到三个选项:

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

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

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

从实现的角度来看,这些都不是特别有吸引力的前景,我可以看到如果可能的话我会避免这样做,特别是因为 Perl 编码人员可以通过使用split.

于 2013-10-03T13:12:44.347 回答
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;

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

要将正则表达式用于行尾,必须解决这些歧义,并且必须施加额外的限制(例如,只允许使用常规语言)。

于 2013-10-03T13:16:53.027 回答
0

Perl6:: Slurp 看起来像是一种可能的解决方法:

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

于 2013-10-03T12:23:15.123 回答