【问题标题】:What characters are allowed in Perl identifiers?Perl 标识符中允许使用哪些字符?
【发布时间】:2011-06-15 13:50:10
【问题描述】:

我正在做正则表达式作业,其中一个问题是:

使用在线语言参考手册确定 Java、Python、Perl 和 C 的整数数字常量和标识符的正则表达式。

我不需要关于正则表达式的帮助,我只是不知道 Perl 中的标识符是什么样的。我找到了描述CPythonJava 的有效标识符的页面,但我找不到关于 Perl 的任何信息。

编辑:澄清一下,查找文档很容易(例如在 Google 上搜索 python identifiers)。我没有参加“进行 Google 搜索”的课程。

【问题讨论】:

  • 关于您的说明:您是否搜索过“perl 标识符”?也许尝试引用它?答案结果不在顶部,但也不低或难以识别。 tchrist 的回答当然值得一问。 :)
  • man perlvar 应该足够了,嗯?
  • @Ashley: google.com/search?q=%22perl+identifiers%22 我没有看到任何看起来有用的东西。很多 Perl 示例,以及对变量名称的不完整描述(基本上它们以 $ 开头)。我真的没想到会这么难回答。希望它会在未来对人们有所帮助,因为 SO 往往会出现在 Google 搜索的顶部附近。
  • 变量和标识符是有区别的。 Perl 中的变量以三个符号之一开始——$@%——前两个可以选择带下标。标识符也可以以*& 开头,但它们不是变量。此外,诸如子例程、格式以及文件和目录句柄之类的东西是标识符,而不是变量。当您以与格形式说print STDERR "oops!\n" 或等效的STDERR‑>print("oops") 时,printSTDERR 都是同义词,但没有印记。 (印记是[$@%&*] 之一。)

标签: perl unicode identifier


【解决方案1】:

没有官方规范(Perl 是 perl 解释器可以解析的任何东西),这些可能有点难以辨别。

This page 有所有整数常量格式的示例。标识符的格式需要从 perldoc 中的各个页面推断出来。

【讨论】:

  • 还要注意,任何假装存在负常数之类的东西都无法理解语法;只需运行perl -MO=Concise,-exec -le '$x = -3**$y' 即可找出原因。
  • Perl6 实际上是规范的,但是是的...... Perl5 和更早的版本确实使用“语言就是编译器所说的”方法。
  • @Autocracy:这夸大了问题。
【解决方案2】:

作业要求你使用参考手册,所以我会用这些术语来回答。

Perl 文档位于http://perldoc.perl.org/。处理变量的部分是 perldata。这很容易给你一个有用的答案。

实际上,我怀疑文档中是否提供了完整的答案。有特殊变量(见 perlvar)和“使用 utf8;”会极大地影响“字母”和“数字”的定义。

$ perl -E'use utf8; $é=123; say $é'
123

[ 我只介绍了标识符部分。我只是注意到问题比那个更大]

【讨论】:

  • 赋值的重点是写正则表达式。这所学校的老师可能只是假设我们都知道 Perl,尽管这里的任何课程都没有教授它(如果我知道 Python,为什么还要学习 Perl?)。
  • 学习新语言总是好的。它为您提供了有关如何解决许多问题的全新视角。
  • @Brendan:重点是您可以实时完成真正的工作。
  • @Brendan - Perl 和 Python 就可用性而言可能在某种程度上可以互换,但并非总是如此(除了语言比较,库集不同)。我强烈建议两者都学习(如果你已经熟悉 Python,学习 Perl 不应该过于复杂)。
  • @Brendan:与 Perl 相比,Python 正则表达式的“错误”与其说是它们所缺乏的不如说是:真正且完整的 Unicode 支持,包括没有这种广泛的构建杂物,UTS#18 standards compliancestructured a.k.a. grammatical regexes用于将声明与执行分离,递归 s/\((?:[^()]*+|(?0))*\)//g 以剥离嵌套括号,剪裁属性和大小写,回溯控制,调试和仪表,&c&c&c!
【解决方案3】:

Perl 文档的 perlvar 页面末尾有一个section,大致概述了允许的语法。总结:

  1. 字母、数字、下划线和特殊序列::(或')的任意组合,前提是它以字母或下划线开头。
  2. 一个数字序列。
  3. 单个标点符号。
  4. 单个控制字符,也可以写为插入符号-{letter},例如^W
  5. 以控制字符开头的字母数字字符串。

请注意,除了 set 1 中的标识符之外,大多数标识符要么被 Perl 赋予了特殊含义,要么被保留并可能在以后的版本中获得特殊含义。但是,如果您只是想弄清楚什么是有效标识符,那么这对您来说并不重要。

【讨论】:

  • @mscha:作业是创建一个正则表达式。自己查找文档充其量只是分散注意力。
  • 恐怕这代表了现实的非常简化版。您将不得不检查词法分析器的 scan_ident 函数,以及 UTF8_IS_STARTisALNUM_utf8UTF8_IS_CONTINUED 宏。对于第一个近似值,标识符是其中仅包含 Alphabetic、Mark、Decimal_Number 或 Connector_Punctuation 类型字符的东西。您还忘记了 MJD 风格的变量,例如 ${^TAINT}${^UNICODE}。但这并不意味着你不能有${ "!##%^&--!!" } 类型的变量;这些是完全有效的。它们不能是词汇。 HTH&&HAND!
  • @tchrist: ^TAINT(以及类似的^UNICODE)是集合 5 的示例 - 以控制字符开头的字母数字字符串。此外,提问者的任务似乎是根据语言参考生成正则表达式,而不是根据实际情况(这是一项更具挑战性的任务)。
  • @mscha - 在 Perl 的情况下,没有经验的人将无法从文档中提出有用的正确完整定义。 blah blah blah 只有 perl 可以解析 Perl blah blah blah。请记住,此评论来自那些容易对人们在 SO 上提出硬件问题的人大喊大叫,投反对票,并通过拒绝发布需要 1 秒才能撰写的硬件答案而放弃简单的投票。
  • @DVK:我的硬件回答花了我超过 1 秒的时间来撰写。 :)
【解决方案4】:

Perl 整数常量

Perl 中的整数常量可以是

  • 如果它们以^0x 开头,则以 16 为基数
  • 如果它们以^0b 开头,则以 2 为基数
  • 如果它们以 0 开头,则以 8 为基数
  • 否则它们以 10 为底。

在该前导之后是该基数中任意数量的有效数字以及可选的下划线

注意数字不代表\p{POSIX_Digit};它的意思是\p{Decimal_Number},这真的很不一样,你知道的。

请注意,任何前导减号不是整数常量的一部分,这很容易证明:

$ perl -MO=Concise,-exec -le '$x = -3**$y'
1  <0> enter 
2  <;> nextstate(main 1 -e:1) v:{
3  <$> const(IV 3) s
4  <$> gvsv(*y) s
5  <2> pow[t1] sK/2
6  <1> negate[t2] sK/1
7  <$> gvsv(*x) s
8  <2> sassign vKS/2
9  <@> leave[1 ref] vKP/REFC
-e syntax OK

看到 3 const,以及很久以后的 negate 操作码?这会告诉你很多信息,包括对优先级的好奇。

Perl 标识符

通过符号解引用指定的标识符对它们的名称绝对没有任何限制

  • 例如,100-&gt;(200) 使用参数(100, 200) 调用名为100 的函数。
  • 另一方面,${"What’s up, doc?"} 在当前包中通过该名称引用标量包变量。
  • 另一方面,${"What's up, doc?"} 指的是名称为${"s up, doc?"} 的标量包变量,它在当前包中不是,而是在What 包中。当然,除非当前包是What 包。与$Who's 类似的是Who 包中的$s 变量。

也可以有${^标识符}形式的标识符;这些不被视为对符号表的符号取消引用。

单个字符的标识符可以是标点符号,包括$$%!

标识符也可以是$^C 的形式,它可以是控制字符或后跟非控制字符的抑扬符。

如果这些都不成立,则(非完全限定)标识符遵循与具有属性 ID_Start 的字符相关的 Unicode 规则,然后是具有属性 ID_Continue 的字符。但是,它推翻了这一点,允许全数字标识符和以下划线开头(并且可能没有其他内容)的标识符。您通常可以假装(但实际上只是假装)这就像说\w+,其中\wAnnex C of UTS#18 中的描述相同。也就是说,任何有这些的东西:

  • Alphabetic 属性——它不仅仅包括字母;它还包含各种组合字符和 Letter_Number 代码点,以及带圆圈的字母
  • Decimal_Number 属性,它不仅仅是[0-9]
  • 任何和所有具有 Mark 属性的字符,而不仅仅是那些被视为 Other_Alphabetic 的标记
  • 任何具有 Connector_Puncutation 属性的字符,下划线就是其中之一。

所以要么^\d+$ 要么

^[\p{Alphabetic}\p{Decimal_Number}\p{Mark}\p{Connector_Punctuation}]+$

如果您不想探索 Unicode ID_Start 和 ID_Continue 属性的复杂性,则应该为真正简单的那些做它。这就是它的真正完成方式,但我敢打赌你的教练不知道这一点。也许有人不会告诉他,嗯?

但你应该涵盖我之前描述的不简单的那些。

而且我们还没有讨论包。

标识符中的 Perl 包

除了这些简单的规则之外,您还必须考虑标识符可以用包名来限定,而包名本身遵循标识符的规则。

包分隔符是::',随心所欲。

如果包是完全限定标识符中的第一个组件,则不必指定包,在这种情况下,它表示包main。这意味着像$::foo$'foo 等价于$main::foo,而isn't_it() 等价于isn::t_it()(Typo removed)

最后,作为一种特殊情况,允许在哈希末尾使用尾随双冒号(但不是单引号),然后 this 引用该名称的符号表。

因此%main::main 符号表,因为您可以省略main,所以%:: 也是如此。

同时,%foo::foo 符号表,%main::foo::%::foo:: 也是为了变态。

总结

很高兴看到教师给人们布置非平凡的任务。问题是教练是否意识到这不是微不足道的。应该不会吧。

而且不仅仅是 Perl。关于 Java 标识符,您是否发现教科书在撒谎?这是演示:

$ perl -le 'print qq(public class escape { public static void main(String argv[]) { String var_\033 = "i am escape: ^\033"; System.out.println(var_\033); }})' > escape.java
$ javac escape.java
$ java escape | cat -v
i am escape: ^[

是的,这是真的。许多其他代码点也是如此,特别是如果您在编译行上使用-encoding UTF-8。您的工作是找到描述这些令人吃惊的不受禁止的 Java 标识符的模式。 提示:确保包含代码点 U+0000。

你不高兴你问了吗?希望这可以帮助。或者其他的东西。 ☺

【讨论】:

  • 请注意 Brendan - 如果你真的想向你的老师展示这个 War and Piece 大小的答案,作为说明为什么你的 Perl 标识符正则表达式需要 2 整页的文档的一部分,他开始质疑被引用的人,告诉他提供答案的人可以很容易地写一本关于 Perl 编程的书。
  • 哇,这很难。不过非常感谢。我读到的 Java 文章说它们可以由字母、数字或基本上任何 unicode 字母组成。对于那个我只是假设为我定义了“javaletters”。但是为什么 U+000 是一个有效的字符呢?只是为了让用 C 语言编写 Java 编译器变得困难? :D
  • @Brendan:我敢肯定你的导师也不认为会这么难。我担心,就像在许多学术追求中一样,获得好成绩的最佳方法是给出你期望的答案,而不是试图准确地模拟一个比给出作业的人复杂得多的现实的答案想象中的。
  • @Brendan:关于Java,我真的不知道。这是我偶然发现的。很多丑陋的非\w 控制字符;这是可耻的。我编写了一个 Perl 程序,它详尽地尝试编译 Java 标识符中所有可能的代码点,如果我能看到这种模式,我会被诅咒的。这很荒谬,但其中混入了足够多的模式(例如,属性\p{Sc} 的代码点,即 Currency_Symbol),让您怀疑是否有人没有故意做某事。但他们似乎把事情搞砸了。这就是我现在所知道的。
  • @tchrist - 作为一个 SO 问题可能值得提出。有人可能知道这个想法是什么
猜你喜欢
  • 2018-05-21
  • 2010-12-30
  • 2016-04-13
  • 2018-02-07
  • 2011-10-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多