使用 Perl 前瞻断言查找单个列表

Using Perl look-ahead assertion to find individual list

给出这样的列表:

direct_SQL_statement ::=
  directly_executable_statement semicolon

directly_executable_statement ::=
    direct_SQL_data_statement
  | SQL_schema_statement
  | SQL_transaction_statement
  | SQL_connection_statement
  | SQL_session_statement
  | direct_implementation_defined_statement

direct_SQL_data_statement ::=
    delete_statement__searched
  | direct_select_statement__multiple_rows
  | insert_statement
  | update_statement__searched
  | truncate_table_statement
  | merge_statement
  | temporary_table_declaration

direct_implementation_defined_statement ::=
  "!! See the Syntax Rules."

apostrophe ::=
  "'"
/*
5.2     token and separator

Function

Specify lexical units (tokens and separators) that participate in SQL language.


Format
*/
token ::=
    nondelimiter_token
  | delimiter_token

identifier_part ::=
    identifier_start
  | identifier_extend
/*
identifier_start ::=
  "!! See the Syntax Rules."
identifier_extend ::=
  "!! See the Syntax Rules."
*/
large_object_length_token ::=
  digit+ multiplier

是否可以使用 Perl 的先行断言将其分解为单独的定义列表?

我试过了,

perl -0777ne 'print "$&\n^^\n\n" while /(?=\w+\s*::=)\w+\s*::=\s*.+/gs;'

但它只是返回了全部内容(好像前瞻断言根本不起作用),而

perl -0777ne 'print "$&\n^^\n\n" while /(?=\w+\s*::=)\w+\s*::=\s*.+?/gs;'

出现太短了:

direct_SQL_statement ::=
  d
^^

directly_executable_statement ::=
    d
^^

direct_SQL_data_statement ::=
    d
^^

direct_implementation_defined_statement ::=
  "
^^

我需要将它分解成单独的 BNF 定义块以进一步处理,就像这样对于初始测试数据:

direct_SQL_statement ::=
  directly_executable_statement semicolon
^^


directly_executable_statement ::=
    direct_SQL_data_statement
  | SQL_schema_statement
  | SQL_transaction_statement
  | SQL_connection_statement
  | SQL_session_statement
  | direct_implementation_defined_statement
^^


direct_SQL_data_statement ::=
    delete_statement__searched
  | direct_select_statement__multiple_rows
  | insert_statement
  | update_statement__searched
  | truncate_table_statement
  | merge_statement
  | temporary_table_declaration
^^


direct_implementation_defined_statement ::=
  "!! See the Syntax Rules."
^^

注释,

可能需要省略的注释 (/* ... */):

perl -0777 -wnE'say for m{(.*?::=.*?)\n (?: \n+ | (?:/\*.*?\*/) | \z)}gsx' bnf.txt

这会捕获带有 ::= 的行及其后的所有内容:更多换行符,或 /*...*/ 注释,或字符串结尾。

修饰符 /s 使 . 也匹配换行符,它通常不匹配,因此 .*? 可以匹配多行文本。 /x 文字空格将被忽略,可用于提高可读性。

或者,先删除注释,然后将输入字符串拆分为多个换行符

perl -0777 -wnE's{ (?: /\* .*? \*/ ) }{\n}gsx; say for split /\n\n+/;' bnf.txt

我认为不需要前瞻。


此 post 的原始版本使用了 paragraph mode,通过 -00,或将整个输入拆分为多个换行符的正则表达式。

这非常简单明了 -- 使用问题原始版本的输入,即没有评论。然后添加的评论可能有空行,并且段落中的阅读不再有效,因为会引入虚假的评论。

我正在下面恢复它,因为它被认为有用 --

如果始终有空行分隔感兴趣的块,则可以处理 in paragraphs

perl -00 -wne'print' file

这会保留空行,您似乎无论如何都想保留它。如果没有,可以去掉。

(然后好奇埃文可以简单地做perl -00 -pe'1' file

否则,可以在多个换行符上断开该字符串

perl -0777 -wnE'@chunks = split /\n\n+/; say for @chunks' file

或者,如果您确实需要输出它们

perl -0777 -wnE'say for split /\n\n+/' file

块之间的空行现已删除。

我看不出有什么理由要提前看一下。


我意识到“BNF 定义”可能是行 之后::=。在那种情况下,一种方式

perl -0777 -wnE'say for /(.+?::=.*?)\n(?:\n+|\z)/gs' file

但是,需要省略可能的注释 (/* ... */):

perl -0777 -wnE'say for m{(.*?::=.*?)\n (?: \n+ | (?:/\*.*?\*/) | \z)}gsx' bnf.txt


提醒:所有对 post 的修订都可以通过 post 正下方的 link 查看,以及 [=] 的文本30=].