【问题标题】:Why doesn't Perl support the normal [] operator to index a string?为什么 Perl 不支持普通的 [] 运算符来索引字符串?
【发布时间】:2010-12-12 07:39:27
【问题描述】:

为什么 Perl 不支持普通的 [] 运算符来索引字符串?

几乎所有主要的编程语言都支持此运算符,尤其是另外两个“P”:Python 和 PHP。此外,我确实认为实现这个小语法应该很容易。另外,作为 Perl 编程语言的哲学——我们尽可能地懒惰,那么我们为什么还要费心使用函数来索引字符串呢?

Perl 6 会支持这种语法吗?

【问题讨论】:

  • 这不是一个功能。这只是语法。
  • [] 一点都不“正常”。不仅如此,[] 可能会也可能不会被实现为一个函数,尽管它是语法(例如,在 Ruby 中[] 实际上是一个方法)。
  • 旁注:Perl、Python 和 PHP 不需要共享任何特性或语法。这三种语言有非常不同的语法、非常不同的语义和非常不同的设计目标。如果您期望它们相同,那么您将大失所望。 (例如,在 Haskell 中,从字符串中提取第 n 个字符或从任何列表中提取第 n 项的运算符是 $$。没有人抱怨 Haskell 没有为此目的使用 []...)
  • @Daniel:不太正确,Haskell 使用!!。更多示例:SML 使用String.sub,Caml 使用String.get(或.[]),J 使用{~,XSLT 使用substring,Java 使用.charAt()

标签: perl string indexing


【解决方案1】:

到目前为止,我喜欢所有的答案,但真正的答案是,“因为拉里想要那样”。真的。 Larry 想出了一套对他有用的习语和工具,他以 Perl 的形式与我们分享了这些。如果您的想法与拉里的想法不同,那么还有很多其他工具可以使用。我们不需要全世界都在使用 Perl……只需要像 Larry 那样“得到它”的人。

【讨论】:

  • 是的,但是拉里的理由是什么?也许你有一些见解?
【解决方案2】:

使用[] 对字符串进行索引是许多编程语言处理字符串的方式的副作用:作为字符数组(或在Unicode 的情况下为宽字符)。在 Perl 中,字符串是一流的实体。 Perl 提供了许多将整个字符串作为单个值处理的方法。如果你试图索引一个字符串,你可能做错了什么。 (例如,用 Perl 编写 C 而不是使用 Perl 惯用语。)对于确实需要对字符串进行索引的情况,请使用 substr

【讨论】:

  • 字符串是一等实体(与简单的字符数组相反)并不意味着它不能在语法上被视为数组。例如,参见 Java、C# 和 Delphi。
【解决方案3】:

您要按字节、字符还是字素索引?

这就是为什么在 Perl 6 length is "banned" 中,您使用以下之一:

  • bytes
    一次只有一个字节
  • chars
    根据源文本,这可以是单个字节,也可以是多个字节。
  • graphs
    这类似于 chars,但将多个“组合”字符组合在一起。

如果你真的想要它,你可以做类似的事情,使用split

( split '', $str )[$index];

不过,最好只使用substr

substr $str, $index, 1;

【讨论】:

  • 我会写(split //, $str)[$index],因为这样可以避免建立不必要的匿名列表,但两者看起来都有些奇怪,不是吗? substr($str, $index, 1)(或 $str.substr($index, 1),在 Perl 6 中)在可读性方面可能是最好的。
  • 对于那些对“split undef”感到困惑的人,split 可以采用 //-notation 中的正则表达式(例如split /foo/)或任何应该被解释为正则表达式的表达式(例如@987654336 @)。 undef 被提升为空字符串并编译为正则表达式,产生与split // 相同的结果,除了“使用未初始化的值”警告。 (另一个区别是 perl 必须在每次执行拆分时都尝试编译正则表达式,而不是只编译一次。)
  • 我在这里使用split '', ... 而不是split //, ...,因为代码高亮显示有问题。
【解决方案4】:

Perl 可以使用indexsubstr 来索引字符串。它支持操作。它用另一种语法来做到这一点并不重要。我们拥有不止一种编程语言是有原因的。 :)

我不会说 [] 是“普通”运算符。我相信人们可以列出许多不这样做的语言。

【讨论】:

  • 添加一行描述“另一种语法”会有所帮助
  • 有人抱怨布赖恩的回答缺乏细节,这有点讽刺:) 我将编辑布赖恩的回答,以包含下面评论中建议的语法。
  • ...顺便说一句,具有讽刺意味的原因是 brian 似乎是其他 Perl Qs 和 As 最多产的编辑,经常添加澄清细节。
  • 我回滚了编辑并改为链接到 substr。没有更多细节,因为问题不是问如何索引字符串,而是 Perl 为什么不使用特定的语法。
  • 顺便说一句,好的写作来自好的编辑。由于 SO 的目标是通过 Google 提供优质信息,因此我一直在编辑自己的答案。
【解决方案5】:

如果你真的想把标量当作对象,你可以使用autobox

我不使用autobox,但这应该可以:

my $indexed = ('foo'->list)[1];

autobox 具有用于定义用于包装各种数据类型的对象的挂钩。

所以,如果你真的非常想要它,你应该能够使用autobox 创建你自己的字符串类,它允许这样的代码:

my $indexed = 'foo'->[3];

所以,我想你的问题的答案是“为什么 Perl 没有用于字符串索引的 [] 语法?”是“没有人想要它来实现它。”

至于 Perl 6,我没有密切关注,无法给出答案,“如果它不存在并且你真的想要它,你可以自己添加它。”

【讨论】:

  • 它在 Perl 6 中不存在,但我认为您应该能够简单地定义一个 multi method postcircumflex:<[ ]>(Str, Int)(虽然我无法检查,因为 Rakudo 还不支持它)。跨度>
  • ephemient:您可以在 Raku(née Perl 6)中执行此操作,但仅用于访问(应该是 sub postcircumfix:<[ ]>(Str \a, Int \b) { a.substr: b, 1 }。问题是您需要返回一个代理以允许可编辑访问, 但即使使用上面的 sub,my $a = "abc"; $a[2] = 'C' PositionalAT-POS 将优先并失败。 Mixins 可以使 Str 可索引,最终通过 augment 可以为所有字符串启用
【解决方案6】:

在 Perl 中,字符串是标量,因此默认情况下不可下标。您可以使用substr()index() 之类的函数来访问字符串中的特定字符。

除非 Perl 6 通过将字符串更改为 char 数组来打破这一概念,否则我认为不会对此进行任何更改。

【讨论】:

  • 嗯,在 Perl 6 中,标量是对象,所以很可能有一种方法可以做同样的事情。
  • 我愿意进行更改,只要它们不破坏所有现有的东西;)
  • 这可以通过使用autobox 并覆盖[] 运算符来完成。
  • ..现在我看到 daotoad 已经写了一个解决方案来做到这一点。 :)
【解决方案7】:

字符串的名称是什么?它是标量,所以印记显然是$。其余部分遵循标准变量命名标准;比如说$abc

my $abc = 'A string';

由于符号表示表达式的上下文,并且不是名称的一部分,因此我们发生了冲突。

my $def = $abc[2];

不是标量$abc 的第三个字母,而是数组中的第三个元素——共享相同的符号(但具有不同的sigil):@abc

因此,很可能早期设计用于类似脚本的符号解析的表达式已经被赋予了含义。

当然,正如 Brad 的 回答所指出的那样,只有当我们隐含假设是什么使字符串的一部分成为“列表”中的“项目”时,这才有意义.您必须使用的编码越多,这些默认假设的效果就越更糟

您可能会使用autobox 找到您更喜欢的语法:

$string->ch( 2 );

(您必须自己写ch。)但这必然比简单地将括号放在字符串上更冗长。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-07-02
    • 1970-01-01
    • 2010-12-11
    • 1970-01-01
    • 2015-09-26
    • 2015-05-31
    • 2010-09-17
    • 2011-08-18
    相关资源
    最近更新 更多