乐趣区

关于sap:现代-ABAP-编程语言中的正则表达式

在这篇博文中,我想分享古代 ABAP 中正则表达式的最新消息和变动,次要来自 OP 版本 7.55 和 7.56。

以前,在 ABAP 中应用 POSIX 款式的正则表达式或“uniX 的便携式操作系统接口 - POSIX 的全称是 Portable Operating System Interface for uniX”。因而,从当初开始,POSIX 语法中的正则表达式已过期,而后应用这种正则表达式语法会导致语法查看正告。尽管这能够被 pragma ##regex_posix 暗藏,但强烈建议迁徙到 ABAP 反对的其余正则表达式语法,如 PCRE 正则表达式、XPath 正则表达式或 XSD 正则表达式。

ABAP 正则表达式的回顾

正则表达式对于新用户来说通常是简单和令人生畏的。在深入研究新性能之前,我想简要介绍一下 RegEx,并展现用 ABAP 明确编写的示例。如果您是该主题的专家并且可能会感到无聊,请随时跳过此局部。

RegEx 的概念曾经存在了很长一段时间。当须要简单的模式时应用它。如搜寻数字、字母、特殊字符或验证电子邮件等。许多文本搜寻和替换问题在不应用正则表达式模式匹配的状况下很难解决。此外,在 ABAP 中,应用正则表达式的搜寻比传统的 SAP 模式更弱小。让咱们以这个简略的例子为例:

 FIND 'A' IN 'ABCD1234EFG'
  MATCH COUNT sy-tabix.
  WRITE: sy-tabix.

当初,如果您想在不应用 RegEx 的状况下通过失常搜寻模式查找字符串中的所有字母,则须要对所有 26 个字符进行循环。应用 RegEx,能够很容易地搜寻和找到所有七个字符:

FIND ALL OCCURRENCES OF PCRE '[A-Z]' IN 'ABCD1234EFG'
  MATCH COUNT  sy-tabix.
WRITE: sy-tabix.

ABAP 在语句 FIND 和 REPLACE 中以及通过类 CL_ABAP_REGEX 和 CL_ABAP_MATCHER 反对正则表达式。CL_ABAP_MATCHER 类将应用 CL_ABAP_REGEX 生成的正则表达式利用于字符串或外部表。

Greedy or Lazy?

另一个可能乏味的概念是 RegEx 中贪心或惰性量词的含意。在用 (,+,…) 定义的贪心模式中,量化字符被反复尽可能多的次数。RegEx 引擎将尽可能多的字符增加到匹配中,而后一个一个地缩短,以防模式的其余部分不匹配。它的背面将被称为懈怠模式,它匹配尽可能少的字符。例如,在 ABAP 中,通过在 , (.*?) 前面搁置一个问号,您要求子表达式匹配尽可能少的字符。正则表达式的默认行为是贪心的(实际上 POSIX 意味着无奈敞开的贪心量词)。

例子:

DATA(text) = `"Jack" and "Jill" went up the "hill"`.

FIND ALL OCCURRENCES OF PCRE  `"(.*?)"` IN text IGNORING CASE
    RESULTS DATA(result_tab).
IF sy-subrc = 0.
  LOOP AT result_tab ASSIGNING FIELD-SYMBOL(<result>).
    cl_demo_output=>write(substring( val = text off = <result>-offset len = <result>-length)  ).
  ENDLOOP.
ENDIF.
cl_demo_output=>display().

贪心符号“(.)”将整个输出句子作为输入,而懈怠符号“(.?)”给出三个单词“Jack”、“Jill”、“hill”。如果在懈怠的状况下省略表达式“ALL OCCURRENCES OF”,则只会找到第一个“和前面的”之间的子字符串,即“Jack”。

直到 7.55 版本,ABAP 仅将 POSIX 库用于 RegEx。从那时起,也反对 Perl 库。两个库在计算匹配的形式上有很大不同。因为 POSIX 曾经过期,咱们将在下文中应用 Perl 格调的正则表达式。您能够通过在 AS ABAP 中运行报表 DEMO_REGEX 来尝试应用 Regex 来尝试不同的表达式。

PCRE Syntax

PCRE 库是一组用 C 语言编写的函数,它们应用与 Perl 5 雷同的语法和语义实现正则表达式模式匹配,并领有本人的原生 API。PCRE 语法代表“Perl Compatible Regular Expressions”,比 POSIX 语法或许多其余正则表达式库更弱小、更灵便,并且比 ABAP 反对的 POSIX 正则表达式性能更好。

具备 PCRE 语法的 RegEx 能够在 FIND 和 REPLACE 语句的增加 PCRE 和字符串的内置函数的参数 PCRE 之后指定。PCRE 正则表达式的对象能够应用零碎类 CL_ABAP_REGEX 的工厂办法 CREATE_PCRE 创立,用于语句 FIND 和 REPLACE 或应用零碎类 CL_ABAP_MATCHER。

例子:

DATA(text) = `oooababboo`.

FIND PCRE 'a.|[ab]+|b.*' IN text
     MATCH OFFSET DATA(moff)
     MATCH LENGTH DATA(mlen).
IF sy-subrc = 0.
  cl_demo_output=>write(substring( val = text off = moff    len = mlen) ).
ENDIF.

搜寻应用 PCRE 正则表达式语法并从偏移量 3 中找到长度为 2 的“ab”。然而,应用加法 REGEX 而不是 PCRE,搜寻会从偏移量 3 或更高的长度为 5 中找到子字符串“abbabb”。

Callouts in PCRE Regular Expressions

通过 RegEx callouts,能够在正则表达式模式匹配过程中长期将控制权交给函数。PCRE 标注应用语法 (?C…) 指定,其中点代表可选参数。如果你在调用 PCRE 的匹配函数之前指定一个 callout 函数,每当引擎运行到 (?C…) 时,它会临时挂起匹配并将控制权传递给那个 callout 函数,它提供无关匹配的信息。而后调用函数执行它应该做的任何工作,而后它向引擎返回一个代码,让它晓得是否失常进行剩下的较量。

在 ABAP 中,PCRE 语法反对在将正则表达式与 CL_ABAP_MATCHER 匹配期间调用 ABAP 办法的标注。当执行办法 MATCH 时,PCRE 正则表达式的特殊字符 (?C…) 而后调用接口办法 CALLOUT。该示例演示了如何从 PCRE 正则表达式调用 ABAP 办法。

REPORT demo_pcre_callout.

CLASS handle_regex DEFINITION.
  PUBLIC SECTION.
    INTERFACES if_abap_matcher_callout.
ENDCLASS.

CLASS handle_regex IMPLEMENTATION.
  METHOD if_abap_matcher_callout~callout.
    cl_demo_output=>write(|{ callout_num} {callout_string}| ).
  ENDMETHOD.
ENDCLASS.

CLASS demo_pcre DEFINITION.
  PUBLIC SECTION.
    CLASS-METHODS main.
ENDCLASS.

CLASS demo_pcre IMPLEMENTATION.
  METHOD main.
    DATA(regex) = cl_abap_regex=>create_pcre(pattern = `a(?C1)b(?C2)c(?C3)d(?C"D")e(?C"E")` ).

    DATA(matcher) = regex->create_matcher(text = `abcde`).

    DATA(handler) = NEW handle_regex( ).
    matcher->set_callout(handler).
    matcher->match( ).

    cl_demo_output=>display( ).
  ENDMETHOD.
ENDCLASS.

START-OF-SELECTION.
  demo_pcre=>main().

正则表达式蕴含用于标注的特殊字符 (?C…)。前三个标注传递数字数据,其余两个传递字符串数据。

本地类“handle_regex”实现接口 IF_ABAP_MATCHER_CALLOUT 并且该类的实例被设置为标注处理程序。当正则表达式匹配到时,每个 callout 地位都会调用接口办法 CALLOUT,能够拜访传入的参数。

PCRE syntax for ABAP SQL and ABAP CDS

ABAP SQL 和 ABAP CDS 还通过内置函数 REPLACE_REGEXPR、LIKE_REGEXPR 和 OCCURRENCES_REGEXPR 反对 PCRE 语法。这些函数拜访在 SAP HANA 数据库中实现的 PCRE1 库。个别 ABAP 的正则表达式与 ABAP 内核中实现的 PCRE2 库一起应用。

CDS View Entity

此 SQL 函数在字符串中搜寻正则表达式模式,并返回该字符串,其中蕴含应用 CDS 视图实体中的替换字符串替换的正则表达式模式的一次或每次呈现。

REPLACE_REGEXPR(PCRE => pcre,
                VALUE => arg1,
                WITH => arg2,
                RESULT_LENGTH => res[,
                OCCURRENCE => occ][,
                CASE_SENSITIVE => case][,
                SINGLE_LINE => bool][,
                MULTI_LINE => bool][,
                UNGREEDY => bool])

以下 CDS 视图实体将 SELECT 列表中的字符串的内置 SQL 函数利用于 DDIC 数据库表 SPFLI 的列,以应用转换值替换 MI 到 KM 的间隔 id。

@AccessControl.authorizationCheck: #NOT_REQUIRED

define view entity ZI_regex_test

  as select from spfli

{concat_with_space( cityfrom, cityto, 4)    as from_City_to,

  distance                                       as Distance,

  distid                                         as DistanceId,

  case

   when distid = 'MI' then

    replace_regexpr(pcre => '[^<]+',

                       value => distid,

                       with => '1.6 KM',

                       result_length => 6  )

                       else 'KM'

                                             end as DistanceIdInKM

}

SQL Expressions

ABAP SQL 当初反对一些新的正则解决性能。

本示例从 spfli 表中抉择来自柏林或东京的航班,并将它们放在 lt_table 中。

SELECT * FROM spfli
   WHERE
      like_regexpr(pcre = '\bBERLIN\b|\bTOKYO\b', value = cityfrom) = '1'
   INTO @ls_table.
   APPEND ls_table TO lt_table.
ENDSELECT.

以下示例应用正则表达式替换从东京到 Neapel 的航班的目的地“罗马”。

SELECT
  carrid as Airline,
  connid as flightNo,
  deptime as Departure_time,
  cityfrom as Departure,
  replace_regexpr(pcre = '\bROME\b', value = cityto , with = 'Neapel') as Destination
  from spfli where cityfrom = 'TOKYO'  
  into TABLE @data(lt_replace) .

并非所有能够为 ABAP CDS 视图实体(例如 UNGREEDY)中的 REPLACE_REGEXPR 函数指定的参数也能够为 ABAP SQL 指定。此性能能够通过 PCRE 语法自身来实现。

Xpath and XSD Syntax

功能丰富的 PCRE 正则表达式简直能够在所有状况下应用。然而,Perl 应用的正则表达式查问并不能很好地将 XML/HTML 分解成有意义的局部并轻松解析它们。为了解决这个难题,ABAP 还反对 Xpath & XSD 正则表达式,并在外部将其转换为 PCRE 语法。

XPath 代表“XML 门路语言”,是一种用于指定 XML 文档局部的表达式语言。XPath 也可用于构造相似于 XML 的文档,如 HTML。XPath 语法中的正则表达式能够在失常和扩大模式下编译。在扩大模式下,模式的大多数未本义空格(空格和换行符)在字符类之外被疏忽,正文能够放在 # 前面。在 ABAP 内置函数中,扩大模式默认开启,能够通过正则表达式中的 (?-x) 敞开。

与正则表达式不同,咱们在应用 XPath 时不须要提前晓得数据的模式。因为 XML 文档是应用节点结构化的,XPath 应用该构造来浏览节点以返回蕴含咱们正在寻找的节点的对象。

例子:XPath 正则表达式的一个非凡性能是字符集的减法。在以下示例中,从字符集 BasicLatin 中减去字母 a 到 c,第一个匹配项是偏移量为 3 的 d。

FIND REGEX
  cl_abap_regex=>create_xpath2(pattern = '[\p{IsBasicLatin}-[a-c]]' )
  IN 'abcd' MATCH OFFSET DATA(moff).

与 PCRE 相比,XPath 正则表达式容许转义字符 \ 而不仅仅是在特殊字符后面。在以下示例中,带有参数 xpath 的 match 函数会找到 x,而带有参数 pcre 的 match 函数则不会。因而,第一个 FIND 语句在 sy-subrc 中返回值 0,而第二个 FIND 语句返回 4。

DATA(x) = match(val = `abxcd` xpath = `\x`  occ = 1).
DATA(y) = match(val = `abxcd` pcre =  `\x`  occ = 1).

FIND REGEX cl_abap_regex=>create_xpath2(pattern = '\x') IN 'abxcd'.
FIND REGEX cl_abap_regex=>create_pcre(pattern = '\x') IN 'abxcd'.

XSD Syntax

XSD 代表“Xml Schema Definition”,是 XPath 语法的一个子集。与其余正则表达式相比,XML 模式格调有本人的正则表达式语法和专用符号,但性能十分无限。此性能有余不会成为阻碍,因为 XSD 仅用于验证整个元素是否与模式匹配,而不是用于从大数据块中提取匹配项。

XML 模式锚定整个正则表达式。因而,您不能增加正则表达式分隔符,也不须要应用锚点(即结尾的 ^ 和结尾的 $)。正则表达式必须匹配整个元素能力被视为无效元素。点从不匹配换行符,并且模式辨别大小写。XML 正则表达式没有像 \xFF 或 \uFFFF 这样的任何标记来匹配特殊字符,也没有提供指定匹配模式的办法。

非贪心行为没有 XSD 语法。XSD 也无奈应用惰性量词。因为模式锚定在主题字符串的结尾和结尾,并且只返回胜利 / 失败后果,这只是性能问题,导致贪心和懈怠量词之间存在差别。通过将贪心量词更改为惰性量词或反之亦然,不可能使齐全锚定的模式匹配或失败。此外,没有注册或反向援用的子组没有 XSD 语法。

不论其局限性如何,XML 模式正则表达式提供了两个不便的个性。非凡的速记字符类 \i 和 \c 使得匹配 XML 名称变得容易。没有其余正则表达式反对这种可能性。

您不能间接在 FIND & REPLACE 语句中应用 XSD 语法,但您能够应用通过增加 REGEX 的办法 CREATE_XSD 创立的 RegEx 类的对象。

以下示例应用对 PCRE 有效的 XSD 语法,并且找不到任何与 POSIX 匹配的语法。它也实用于 XPath。

DATA(xml) = `<A><B>...<Y><Z>`.

REPLACE ALL OCCURRENCES OF
        REGEX cl_abap_regex=>create_xsd(pattern = `\i\c*`)
        IN xml WITH `option:$0`.
  cl_demo_output=>display(xml).

论断

如前所述,正则表达式能够让您解析字符串或简单的替换操作。它是一个弱小的文本处理工具,可用于扩大您的 ABAP 性能。我心愿我能让你对 RegEx 和 ABAP 中反对的语法,即 PCRE、XPath 和 XSD 有一个粗略的理解。

只管 PCRE 性能更弱小且可在大多数状况下应用,但最好应用 XPath 或 XSD 从 XML 文档中抉择节点或计算值(如字符串、布尔值或数字),以更快更高效。POSIX 语法当初曾经过期,须要迁徙到 ABAP 反对的任何其余正则表达式语法。ABAP SQL 和 ABAP CDS 视图还反对带有上述内置函数的 PCRE 语法。更具体的信息也能够在 ABAP 关键字文档中找到。

退出移动版