REGEX

作者:郑德鼎 约 19 分钟阅读 更新日期:2024-02-22 2 年前更新 标签:ABAP, 开发

正则表达式(Regular Expressions)

正则表达式在其他编程语言中的应用非常广泛,网上资料也非常多,而网上在ABAP语言中应用的资料却很少,尽管各语言中正则表达式语法知识都很类似,但仍然有一些区别,本文主要是简单介绍一下其基本语法。总结一下,方便大家查阅。

欢迎转载,请注明出处,文中不足之处还望指正。(Email:hubin0809@126.com)

一、简要认识

正则表达式就是用一个“字符串”来描述一个特征,然后去验证另一个“字符串”是否符合这个特征。比如表达式“ab+” 描述的特征是“一个 'a' 和任意个 'b' ”,那么 'ab', 'abb', 'abbbbbbbbbb' 都符合这个特征。

正则表达式可以用来:(1)验证字符串是否符合指定特征,比如验证是否是合法的邮件地址。(2)用来查找字符串,从一个长的文本中查找符合指定特征的字符串,比查找固定字符串更加灵活方便。(3)用来替换,比普通的替换更强大。

举例

解释:

1>     '\w+@\w+(\.\w+)+'中 \w 是表示任意一个字母或数字或下划线,+ 表示前面字符个数为一个或多个,@即为’@’字符

2>     matcher参照类cl_abap_matcher,match有匹配的意思,调用静态方法create创建了匹配的对(暂时这么理解,好吧,我承认我不知道怎么形容),然后调用match方法,返回值中’X’表示匹配,SPACE表示不匹配。

具体含义后面会讲到,本程序主要是验证邮件地址是否合法。

二、语法规则

pattern模板,text要匹配的字符,match匹配结果,’X’表示匹配,SPACE表示不匹配。

1、 普通字符

字母、数字、汉字、下划线、以及后面没有特殊定义的标点符号,都是"普通字符"。表达式中的普通字符,在匹配一个字符串的时候,匹配与之相同的一个字符。

2、 转义字符

一些不便书写的字符,采用在前面加 "\" 的方法。例如’.’

3、 能够与 '多种字符' 匹配的表达式

正则表达式中的一些表示方法,可以匹配 '多种字符' 其中的任意一个字符。比如,表达式 "\d" 可以匹配任意一个数字。虽然可以匹配其中任意字符,但是只能是一个,不是多个。这就好比玩扑克牌时候,大小王可以代替任意一张牌,但是只能代替一张牌。(没玩过?好吧,去玩qq够级吧,ok,信息泄露了,承认我是山东人)

4、 自定义能够与 '多种字符' 匹配的表达式

使用方括号 [ ] 包含一系列字符,能够匹配其中任意一个字符。用 [^ ] 包含一系列字符,则能够匹配其中字符之外的任意一个字符。同样的道理,虽然可以匹配其中任意一个,但是只能是一个,不是多个。

5、 支持的 POSIX 字符集合

个人感觉意义不大,可能对一些控制字符有用吧,了解。

6、 修饰匹配次数的特殊符号

前面讲到的表达式,无论是只能匹配一种字符的表达式,还是可以匹配多种字符其中任意一个的表达式,都只能匹配一次。如果使用表达式再加上修饰匹配次数的特殊符号,那么不用重复书写表达式就可以重复匹配,否则会累死的。

7、 其他一些代表抽象意义的特殊符号

进一步的文字说明仍然比较抽象,因此,举例帮助大家理解。

举例1:表达式 "^aaa" 在匹配 "xxx aaa xxx" 时,匹配结果是:失败。因为 "^" 要求与字符串开始的地方匹配,因此,只有当 "aaa" 位于字符串的开头的时候,"^aaa" 才能匹配,比如:"aaa xxx xxx"。

举例2:表达式 "aaa$" 在匹配 "xxx aaa xxx" 时,匹配结果是:失败。因为 "$" 要求与字符串结束的地方匹配,因此,只有当 "aaa" 位于字符串的结尾的时候,"aaa$" 才能匹配,比如:"xxx xxx aaa"。

举例3:表达式 ".\b." 在匹配 "@@@abc" 时,能够找到匹配的内容;匹配到的内容是:"@a";匹配到的位置是:开始于2,结束于4。

进一步说明:"\b" 与 "^" 和 "$" 类似,本身不匹配任何字符,但是它要求它在匹配结果中所处位置的左右两边,其中一边是 "\w" 范围,另一边是 非"\w" 的范围。

举例4:表达式 "\bend\b" 在匹配 "weekend,endfor,end" 时,能够找到匹配的内容;匹配到的内容是:"end";匹配到的位置是:开始于15,结束于18。

三、正则表达式中的一些高级规则(ABAP部分支持)

1、 匹配次数中的贪婪与非贪婪

贪婪模式:

在使用修饰匹配次数的特殊符号时,有几种表示方法可以使同一个表达式能够匹配不同的次数,比如:"{m,n}", "{m,}", "?", "*", "+",具体匹配的次数随被匹配的字符串而定。这种重复匹配不定次数的表达式在匹配过程中,总是尽可能多的匹配。比如,针对文本 "dxxxdxxxd",举例如下:

由此可见,"\w+" 在匹配的时候,总是尽可能多的匹配符合它规则的字符。虽然第二个举例中,它没有匹配最后一个 "d",但那也是为了让整个表达式能够匹配成功。同理,带 "*" 和 "{m,n}" 的表达式都是尽可能地多匹配,带 "?" 的表达式在可匹配可不匹配的时候,也是尽可能的 "要匹配"。这种匹配原则就叫作 "贪婪" 模式 。

非贪婪模式:(ABAP暂时不支持,但是最好理解吧)

在修饰匹配次数的特殊符号后再加上一个 "?" 号,则可以使匹配次数不定的表达式尽可能少的匹配,使可匹配可不匹配的表达式,尽可能的 "不匹配"。这种匹配原则叫作 "非贪婪" 模式,也叫作 "勉强" 模式。如果少匹配就会导致整个表达式匹配失败的时候,与贪婪模式类似,非贪婪模式会最小限度的再匹配一些,以使整个表达式匹配成功。举例如下,针对文本 "dxxxdxxxd" 举例:

更多的情况,举例如下:

举例1:表达式 "<td>(.*)</td>" 与字符串 "<td><p>aa</p></td> <td><p>bb</p></td>" 匹配时,匹配的结果是:成功;匹配到的内容是 "<td><p>aa</p></td> <td><p>bb</p></td>" 整个字符串, 表达式中的 "</td>" 将与字符串中最后一个 "</td>" 匹配。

举例2:相比之下,表达式 "<td>(.*?)</td>" 匹配举例1中同样的字符串时,将只得到 "<td><p>aa</p></td>", 再次匹配下一个时,可以得到第二个 "<td><p>bb</p></td>"。

2、 反向引用 \1, \2

表达式在匹配时,表达式引擎会将小括号 "( )" 包含的表达式所匹配到的字符串记录下来。在获取匹配结果的时候,小括号包含的表达式所匹配到的字符串可以单独获取。这一点,在前面的举例中,已经多次展示了。在实际应用场合中,当用某种边界来查找,而所要获取的内容又不包含边界时,必须使用小括号来指定所要的范围。比如前面的 "<td>(.*?)</td>"。

其实,"小括号包含的表达式所匹配到的字符串" 不仅是在匹配结束后才可以使用,在匹配过程中也可以使用。表达式后边的部分,可以引用前面 "括号内的子匹配已经匹配到的字符串"。引用方法是 "\" 加上一个数字。"\1" 引用第1对括号内匹配到的字符串,"\2" 引用第2对括号内匹配到的字符串……以此类推,如果一对括号内包含另一对括号,则外层的括号先排序号。换句话说,哪一对的左括号 "(" 在前,那这一对就先排序号。

举例如下:

举例1:表达式 "('|")(.*?)\1" 在匹配 " 'Hello', "World" " 时,匹配结果是:成功;匹配到的内容是:" 'Hello' "。再次匹配下一个时,可以匹配到 " "World" "。

举例2:表达式 "(\w)\1{4,}" 在匹配 "aa bbbb abcdefg ccccc 111121111 999999999" 时,匹配结果是:成功;匹配到的内容是 "ccccc"。再次匹配下一个时,将得到 999999999。这个表达式要求 "\w" 范围的字符至少重复5次,注意与 "\w{5,}" 之间的区别。

举例3:表达式 "<(\w+)\s*(\w+(=('|").*?\4)?\s*)*>.*?</\1>" 在匹配 "<td id='td1' style="bgcolor:white"></td>" 时,匹配结果是成功。如果 "<td>" 与 "</td>" 不配对,则会匹配失败;如果改成其他配对,也可以匹配成功。

3、 预搜索

前面的章节中,我讲到了几个代表抽象意义的特殊符号:"^","$","\b"。它们都有一个共同点,那就是:它们本身不匹配任何字符,只是对 "字符串的两头" 或者 "字符之间的缝隙" 附加了一个条件。理解到这个概念以后,本节将继续介绍另外一种对 "两头" 或者 "缝隙" 附加条件的,更加灵活的表示方法。

正向预搜索:"(?=xxxxx)","(?!xxxxx)"

格式:"(?=xxxxx)",在被匹配的字符串中,它对所处的 "缝隙" 或者 "两头" 附加的条件是:所在缝隙的右侧,必须能够匹配上 xxxxx 这部分的表达式。因为它只是在此作为这个缝隙上附加的条件,所以它并不影响后边的表达式去真正匹配这个缝隙之后的字符。这就类似 "\b",本身不匹配任何字符。"\b" 只是将所在缝隙之前、之后的字符取来进行了一下判断,不会影响后边的表达式来真正的匹配。

举例1:表达式 "Windows (?=NT|XP)" 在匹配 "Windows 98, Windows NT, Windows 2000" 时,将只匹配 "Windows NT" 中的 "Windows ",其他的 "Windows " 字样则不被匹配。

举例2:表达式 "(\w)((?=\1\1\1)(\1))+" 在匹配字符串 "aaa ffffff 999999999" 时,将可以匹配6个"f"的前4个,可以匹配9个"9"的前7个。这个表达式可以读解成:重复4次以上的字母数字,则匹配其剩下最后2位之前的部分。当然,这个表达式可以不这样写,在此的目的是作为演示之用。

格式:"(?!xxxxx)",所在缝隙的右侧,必须不能匹配 xxxxx 这部分表达式。

举例3:表达式 "((?!\bstop\b).)+" 在匹配 "fdjka ljfdl stop fjdsla fdj" 时,将从头一直匹配到 "stop" 之前的位置,如果字符串中没有 "stop",则匹配整个字符串。

举例4:表达式 "do(?!\w)" 在匹配字符串 "done, do, dog" 时,只能匹配 "do"。在本条举例中,"do" 后边使用 "(?!\w)" 和使用 "\b" 效果是一样的。

4、 其他补充

1>  在表达式 "\s","\d","\w","\b" 表示特殊意义的同时,其大写字母表示相反的意义

2>  在表达式中有特殊意义,需要添加 "\" 才能匹配该字符本身的字符汇总

四、在ABAP中的应用

规则终于写完了!其实和其他编程语言规则差不多啦!下面结合ABAP讲讲怎么使用吧,Let’s GO!

不过需要注意, SAP只能是ECC6或者更高版本才可以使用正则(ABAP supports POSIX regular expressions as of Release 7.00)

在ABAP中定义了两个类来实现相应功能,分别是

CL_ABAP_REGEX               regex就是regular expression的缩写,里面的方法不是很多,可能用到的也就只有构造方法和REATE_MATCHER这个方法。

CL_ABAP_MATCHER     matcher匹配的意思,也就是说所有的匹配规则都和它有关,里面具体方法,se24去查看

其实正则表达式的应用无外乎三种:验证(是否符合规则)、查找(包含提取)、替换

1、        验证

实例1

解释:CL_ABAP_MATCHER有一个静态方法,直接进行匹配。

2、        查找

实例2

解释:

创建match实例(创建规则),构造方法中有pattern参数输入规则,IGNORE_CASE是否忽略大小写,SIMPLE_REGEX是否使用简单规则(具体参见F1帮助文档),

B.在实例中有FIND_ALL(),FIND_NEXT()方法,可以用来查找。

这个方法是不是太麻烦了啊,不急有简单的方法,其实就是字符串处理中用到的。

实例3

实例4

解释:大家都知道英文字母是单字节的,中文是双字节的,但是在ABAP里面用strlen等方法是区别不出单双字节的,这个实例中讲的不失为一个很好的办法。

3、        替换

实例4

大家肯定会说了,字符串前后没有没替换啊。注意修改的不是W_TEXT本身,他将修改后的值放到了MATCHER->TEXT即match类实例的属性里面,我们只需令W_TEXT = MATCHER->TEXT即可。

修改后

同样这里也有简单方法,字符串处理中的方法也是支持正则的

实例5

4、        方法语句总结

类结

CL_ABAP_MATCHER类里的重要方法

字符串处理中,支持正则的语句

五、补充

这里给出ABAP F1帮助中给出的一个特殊字符的列表,很有用的

Special Characters in Regular Expressions

The following tables summarize the special characters in regular expressions

Escape character

Special character for single character strings

Special characters for character string patterns

Special characters for search strings

Special characters for replacement texts

从上面的列表可以看出,ABAP中对“非贪婪模式”(ABAP啊,你不支持啊,你太贪婪了)和“反向预搜索”暂不支持,希望以后能够赶紧扩展功能吧,毕竟很强大的说。

正则表达式是需要反复修改,最后才能找到最匹配的规则的,为此ABAP Program里也提供了一个,测试用得小程序,SE38里找DEMO_REGEX_TOY运行即可。

在ABAP培训资料里面有一个很有意思的表达式,大家有兴趣可以看一下它能匹配什么文字

以下附上网上的一些资料:

表达式全集

正则表达式有多种不同的风格。下表是在PCRE中元字符及其在正则表达式上下文中的行为的一个完整列表:

常用的正则表达式

正则表达式用于字符串处理、表单验证等场合,实用高效。现将一些常用的表达式收集于此,以备不时之需。

用户名:/^[a-z0-9_-]{3,16}$/

密码:/^[a-z0-9_-]{6,18}$/

十六进制值:/^#?([a-f0-9]{6}|[a-f0-9]{3})$/

电子邮箱:/^([a-z0-9_\.-]+)@([\da-z\.-]+)\.([a-z\.]{2,6})$/

URL:/^(https?:\/\/)?([\da-z\.-]+)\.([a-z\.]{2,6})([\/\w \.-]*)*\/?$/

IP 地址:/^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/

HTML 标签:/^<([a-z]+)([^<]+)*(?:>(.*)<\/\1>|\s+\/>)$/

Unicode编码中的汉字范围:/^[u4e00-u9fa5],{0,}$/

匹配中文字符的正则表达式: [\u4e00-\u9fa5]

评注:匹配中文还真是个头疼的事,有了这个表达式就好办了

匹配双字节字符(包括汉字在内):[^\x00-\xff]

评注:可以用来计算字符串的长度(一个双字节字符长度计2,ASCII字符计1)

匹配空白行的正则表达式:\n\s*\r

评注:可以用来删除空白行

匹配HTML标记的正则表达式:<(\S*?)[^>]*>.*?</\1>|<.*? />

评注:网上流传的版本太糟糕,上面这个也仅仅能匹配部分,对于复杂的嵌套标记依旧无能为力

匹配首尾空白字符的正则表达式:^\s*|\s*$

评注:可以用来删除行首行尾的空白字符(包括空格、制表符、换页符等等),非常有用的表达式

匹配Email地址的正则表达式:\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*

评注:表单验证时很实用

匹配网址URL的正则表达式:[a-zA-z]+://[^\s]*

评注:网上流传的版本功能很有限,上面这个基本可以满足需求

匹配帐号是否合法(字母开头,允许5-16字节,允许字母数字下划线):^[a-zA-Z][a-zA-Z0-9_]{4,15}$

评注:表单验证时很实用

匹配国内电话号码:\d{3}-\d{8}|\d{4}-\d{7}

评注:匹配形式如 0511-4405222 或 021-87888822

匹配腾讯QQ号:[1-9][0-9]{4,}

评注:腾讯QQ号从10000开始

匹配中国大陆邮政编码:[1-9]\d{5}(?!\d)

评注:中国大陆邮政编码为6位数字

匹配身份证:\d{15}|\d{18}

评注:中国大陆的身份证为15位或18位

匹配ip地址:\d+\.\d+\.\d+\.\d+

评注:提取ip地址时有用

匹配特定数字:

^[1-9]\d*$    //匹配正整数

^-[1-9]\d*$   //匹配负整数

^-?[1-9]\d*$   //匹配整数

^[1-9]\d*|0$  //匹配非负整数(正整数 + 0)

^-[1-9]\d*|0$   //匹配非正整数(负整数 + 0)

^[1-9]\d*\.\d*|0\.\d*[1-9]\d*$   //匹配正浮点数

^-([1-9]\d*\.\d*|0\.\d*[1-9]\d*)$  //匹配负浮点数

^-?([1-9]\d*\.\d*|0\.\d*[1-9]\d*|0?\.0+|0)$  //匹配浮点数

^[1-9]\d*\.\d*|0\.\d*[1-9]\d*|0?\.0+|0$   //匹配非负浮点数(正浮点数 + 0)

^(-([1-9]\d*\.\d*|0\.\d*[1-9]\d*))|0?\.0+|0$  //匹配非正浮点数(负浮点数 + 0)

评注:处理大量数据时有用,具体应用时注意修正

匹配特定字符串:

^[A-Za-z]+$  //匹配由26个英文字母组成的字符串

^[A-Z]+$  //匹配由26个英文字母的大写组成的字符串

^[a-z]+$  //匹配由26个英文字母的小写组成的字符串

^[A-Za-z0-9]+$  //匹配由数字和26个英文字母组成的字符串

^\w+$  //匹配由数字、26个英文字母或者下划线组成的字符串

如何写出高效率的正则表达式

如果纯粹是为了挑战自己的正则水平,用来实现一些特效(例如使用正则表达式计算质数、解线性方程),效率不是问题;如果所写的正则表达式只是为了满足一两次、几十次的运行,优化与否区别也不太大。但是,如果所写的正则表达式会百万次、千万次地运行,效率就是很大的问题了。我这里总结了几条提升正则表达式运行效率的经验(工作中学到的,看书学来的,自己的体会),贴在这里。如果您有其它的经验而这里没有提及,欢迎赐教。

为行文方便,先定义两个概念。

误匹配:指正则表达式所匹配的内容范围超出了所需要范围,有些文本明明不符合要求,但是被所写的正则式“击中了”。例如,如果使用\d{11}来匹配11位的手机号,\d{11}不单能匹配正确的手机号,它还会匹配98765432100这样的明显不是手机号的字符串。我们把这样的匹配称之为误匹配。

漏匹配:指正则表达式所匹配的内容所规定的范围太狭窄,有些文本确实是所需要的,但是所写的正则没有将这种情况囊括在内。例如,使用\d{18}来匹配18位的身份证号码,就会漏掉结尾是字母X的情况。

写出一条正则表达式,既可能只出现误匹配(条件写得极宽松,其范围大于目标文本),也可能只出现漏匹配(只描述了目标文本中多种情况种的一种),还可能既有误匹配又有漏匹配。例如,使用\w+\.com来匹配.com结尾的域名,既会误匹配abc_.com这样的字串(合法的域名中不含下划线,\w包含了下划线这种情况),又会漏掉ab-c.com这样的域名(合法域名中可以含中划线,但是\w不匹配中划线)。

精准的正则表达式意味着既无误匹配且无漏匹配。当然,现实中存在这样的情况:只能看到有限数量的文本,根据这些文本写规则,但是这些规则将会用到海量的文本中。这种情况下,尽可能地(如果不是完全地)消除误匹配以及漏匹配,并提升运行效率,就是我们的目标。本文所提出的经验,主要是针对这种情况。

掌握语法细节。正则表达式在各种语言中,其语法大致相同,细节各有千秋。明确所使用语言的正则的语法的细节,是写出正确、高效正则表达式的基础。例如,perl中与\w等效的匹配范围是[a-zA-Z0-9_];perl正则式不支持肯定逆序环视中使用可变的重复(variable repetition inside lookbehind,例如(?<=.*)abc),但是.Net语法是支持这一特性的;又如,JavaScript连逆序环视(Lookbehind,如(?<=ab)c)都不支持,而perl和python是支持的。《精通正则表达式》第3章《正则表达式的特性和流派概览》明确地列出了各大派系正则的异同,这篇文章也简要地列出了几种常用语言、工具中正则的比较。对于具体使用者而言,至少应该详细了解正在使用的那种工作语言里正则的语法细节。

先粗后精,先加后减。使用正则表达式语法对于目标文本进行描述和界定,可以像画素描一样,先大致勾勒出框架,再逐步在局步实现细节。仍举刚才的手机号的例子,先界定\d{11},总不会错;再细化为1[358]\d{9},就向前迈了一大步(至于第二位是不是3、5、8,这里无意深究,只举这样一个例子,说明逐步细化的过程)。这样做的目的是先消除漏匹配(刚开始先尽可能多地匹配,做加法),然后再一点一点地消除误匹配(做减法)。这样有先有后,在考虑时才不易出错,从而向“不误不漏”这个目标迈进。

留有余地。所能看到的文本sample是有限的,而待匹配检验的文本是海量的,暂时不可见的。对于这样的情况,在写正则表达式时要跳出所能见到的文本的圈子,开拓思路,作出“战略性前瞻”。例如,经常收到这样的垃圾短信:“发*票”、“发#漂”。如果要写规则屏蔽这样烦人的垃圾短信,不但要能写出可以匹配当前文本的正则表达式 发[*#](?:票|漂),还要能够想到 发.(?:票|漂|飘)之类可能出现的“变种”。这在具体的领域或许会有针对性的规则,不多言。这样做的目的是消除漏匹配,延长正则表达式的生命周期。

...

来源说明:本文内容由「REGEX.docx」整理生成,仅用于内部技术分享与学习交流。

ABAP Cheat Sheet 补充内容

以下内容整理自 SAP 官方 ABAP 速查表(主题:Regular Expressions),作为本文的扩展补充资料。

Regular Expressions in ABAP

Introduction

Regular expressions

[!NOTE] - You can perform complex searches using regular expressions. For simple pattern-based searches, refer to comparison operators (CP, NP) in the String Processing cheat sheets. - The cheat sheet and examples focus on PCRE regular expressions. For other syntax types, find more information and links in the ABAP Keyword Documentation. - In a system supporting classic ABAP, you can check out the demo_regex_toy program for experimenting with regular expressions in ABAP.

⬆️ back to top

Excursion: Common Regular Expressions

[!NOTE] - The sections below provide an overview of common PCRE expressions with examples. This is not a comprehensive overview; only selected regular expressions are included. - For a complete guide to PCRE syntax, refer to the official documentation. Note that ABAP-specific restrictions or modifications may apply to the standard syntax. - The code snippets use replace functions to show the effects of PCRE regular expressions. Many examples use the occ parameter with the assignment occ = 0 to replace all occurrences. - When using regular expressions, note that exceptions such as of type cx_sy_invalid_regex or cx_sy_regex_too_complex can occur.

Characters and Character Types

ExpressionRepresentsExample RegexExample StringMatchesDoes not Match
xSpecific characteraabcdefaAnything else
.Any character except a line break (unless in dotall mode, then any character).ab 1#a, b, the blank, 1, #ab, 1#
\dAny digit (0-9), alternative: [0-9]\da1-b2 3-4c91, 2, 3, 4, 9a, b, c, the blank and hyphens
\DAny non-digit, alternative: [^0-9]\Da1-b2 3-4c9a, b, c, the blank and hyphens1, 2, 3, 4, 9
\sAny whitespace character such as a blank, tab and new line\s(hi X )The blanksh, i, X, (, )
\SAny character that is not a whitespace\S(hi X )h, i, X, (, )The blanks
\wAny word character (letter, digit or the underscore), alternative: [a-zA-Z0-9_]\w(ab 12_c)a, b, c, 1, 2, _(, ), the blank
\WAny character that is not a word character, alternative: [^a-zA-Z0-9_]\W(ab 12_c)(, ), the blanka, b, c, 1, 2, _

Examples:

DATA string_chars_types TYPE string.

"Specific character
"#bcdef
string_chars_types = replace( val = `abcdef` pcre = `a` with = `#` occ = 0 ).

"Any character except a line break
"_______ (7 replacements before the line break)
"____ (4 replacements after the line break)
string_chars_types = replace( val = |ab 1#?C\n D23| pcre = `.` with = `_` occ = 0 ).

"Any digit
"a#-b# #-#c#
string_chars_types = replace( val = `a1-b2 3-4c9` pcre = `\d` with = `#` occ = 0 ).

"Any non-digit
"#1##2#3#4#9
string_chars_types = replace( val = `a1-b2 3-4c9` pcre = `\D` with = `#` occ = 0 ).

"Any whitespace character such as a blank, tab and new line
"ab#cd#ef#gh
string_chars_types = replace( val = |ab cd\tef\ngh| pcre = `\s` with = `#` occ = 0 ).

"Any character that is not a
"String template representation of the result: |## ##\t##\n##|
string_chars_types = replace( val = |ab cd\tef\ngh| pcre = `\S` with = `#` occ = 0 ).

"Any word character (letter, digit or the underscore)
"(## ####)
string_chars_types = replace( val = `(ab 12_c)` pcre = `\w` with = `#` occ = 0 ).

"Any character that is not a word character
"#ab#12_c#
string_chars_types = replace( val = `(ab 12_c)` pcre = `\W` with = `#` occ = 0 ).

⬆️ back to top

Escaped Characters and Special Variants

Note that some of the example strings are represented by string templates.

ExpressionRepresentsExample RegexExample StringMatchesDoes not Match
\...To include special characters like [] \ / ^, use \ to escape them. Use \. to match a period (".")..\.ab.cd.efab.cd.efab.cd.ef
\nLine feed (negation \N for non-line feeds)\n\D\\nabc\n123\\\na\\\n1\
\tTab\t\d\\tabc\t123\\\t1\\\ta\
\rCarriage return\r\s\\rabc\r 123\\\r \\\ra\
\RLine feed sequence, ensuring that regular expression matches all kinds of newlines, such as \n, \r, or \r\n (carriage return followed by line feed)\R.\abc\rdef\nghi\r\njkl mno\\\rd\, \\ng\, \\r\nj\\m\
\x{...}Character with hex code\x{00A0}# (non-breaking space and #)\#{ cl_abap_conv_codepage=>create_in( codepage = \UTF-16BE\ )->convert( source = CONV xstring( \00A0\ ) ) }#\The non-breaking space plus the second # characterThe first # character
\N{U+...}Character with Unicode code point\N{U+00A0}# (non-breaking space and # as above)See the example belowSee the example below
\p{..}Character with a specified Unicode character property; see the documentation for options; among them, there are, for example, properties for lowercase (Ll) and uppercase (Lu) letters; negation: \P{..}1. \p{Ll}+
2. \p{Lu}+
3. \P{Lu}+
Hello ABAP1. Hello ABAP
2. Hello ABAP
3. Hello ABAP (the space is also matched)
1. Upper case letter sequences
2. Lower case letter sequences
3. Upper case letter sequences

Examples:

DATA string_esc_chars TYPE string.

"Special characters
"a#b#c#d#e#f#g
string_esc_chars = replace( val = `a[b]c\d/e^f.g` pcre = `\[|\]|\\|\/|\^|\.` with = `#` occ = 0 ).

"Line feeds
"a#b#c
string_esc_chars = replace( val = |a\nb\nc| pcre = `\n` with = `#` occ = 0 ).

"Line feed negation
"String template representation of the result: |#\n#\n#|
string_esc_chars = replace( val = |a\nb\nc| pcre = `\N` with = `#` occ = 0 ).

"Tabs
"a#b#c
string_esc_chars = replace( val = |a\tb\tc| pcre = `\t` with = `#` occ = 0 ).

"Carriage return
"d#e#f
string_esc_chars = replace( val = |d\re\rf| pcre = `\r` with = `#` occ = 0 ).

"Characters with hex code
"The example string includes a non-breaking space.
"#x#
string_esc_chars = replace( 
  val = |#{ cl_abap_conv_codepage=>create_in( codepage = `UTF-16BE` )->convert( source = CONV xstring( `00A0` ) ) }#|
  pcre = `\x{00A0}` with = `x` occ = 0 ).

"Characters with Unicode code point
"As above, the example string includes a non-breaking space.
"The PCRE syntax uses the control verb (*UTF) to enable UTF mode.
"#y#
string_esc_chars = replace( 
  val = |#{ cl_abap_conv_codepage=>create_in( codepage = `UTF-16BE` )->convert( source = CONV xstring( `00A0` ) ) }#|
  pcre = `(*UTF)\N{U+00A0}` with = `y` occ = 0 ).

"Characters with a specified Unicode character property
"H# ABAP
string_esc_chars = replace( val = `Hello ABAP` pcre = `\p{Ll}+` with = `#` occ = 0 ).

"#ello #
string_esc_chars = replace( val = `Hello ABAP` pcre = `\p{Lu}+` with = `#` occ = 0 ).

"#ello#
string_esc_chars = replace( val = `Hello ABAP` pcre = `\P{Ll}+` with = `#` occ = 0 ).

"H#ABAP
string_esc_chars = replace( val = `Hello ABAP` pcre = `\P{Lu}+` with = `#` occ = 0 ).

⬆️ back to top

Quantifiers, Repetitions and Alternatives

ExpressionRepresentsExample RegexExample StringMatchesDoes not Match
x*Zero or more repetitions of xab*abc abbc abbbc a acabc abbc abbbc a acabc abbc abbbc a ac
x+One or more repetitions of xab+abc abbc abbbc a acabc abbc abbbc a ac... a ac
x{m,n}Between m and n repetitions of xab{2,3}abc abbc abbbc a acabc abbc abbbc a acabc ...
x{m}Exactly m repetitionsab{3}abc abbc abbbc a acabc abbc abbbc a acabc abbc ...
x{m,}Exactly m or more repetitionsab{2,}abc abbc abbbc a acabc abbc abbbc a acabc ...
x?Optional x, i.e. zero or one timeab?abc abbc abbbc a acabc abbc abbbc a ac... ac
`x\y`Matching alternatives, i. e. x or y1. `b\2 <br> 2. b(a\u)t`1. abc 123
2. bit bat but bet
1. b, 2
2. bat, but
1. a, c, 1, 3
2. bit, bet
x*?x<em> captures greedily, i.e. as much as possible, while x</em>? captures non-greedily, i.e. as few as possible1. bc<em>?
2. a.</em>?#
1. abcd abccccd ab
2. abc#defgh#i
1. abcd abccccd ab
2. abc#defgh#i
1. abcd abccccd ab (result for bc<em>)
2. abc#defgh#i (result for a.</em>#)
x+?Same as above: x+ (greedy), x+? (non-greedy)1. bc+?
2. <.+?>
1. abcd abccccd ab
2. <span>Hallo</span> html.
1. abcd abccccd ab
2. <span>Hallo</span> html.
1. abcd abccccd ab (result for bc+)
2. <span>Hallo</span> html. (result for <.+>)

Examples:

DATA string_quan_rep_alt TYPE string.

"Zero or more repetitions
"#c #c #c # #c
string_quan_rep_alt = replace( val = `abc abbc abbbc a ac` pcre = `ab*` with = `#` occ = 0 ).

"One or more repetitions
"#c #c #c a ac
string_quan_rep_alt = replace( val = `abc abbc abbbc a ac` pcre = `ab+` with = `#` occ = 0 ).

"Between x and y repetitions
"abc #c #c a ac
string_quan_rep_alt = replace( val = `abc abbc abbbc a ac` pcre = `ab{2,3}` with = `#` occ = 0 ).

"Exactly n repetitions
"abc abbc #c a ac
string_quan_rep_alt = replace( val = `abc abbc abbbc a ac` pcre = `ab{3}` with = `#` occ = 0 ).

"Exactly n or more repetitions
"abc #c #c a ac
string_quan_rep_alt = replace( val = `abc abbc abbbc a ac` pcre = `ab{2,}` with = `#` occ = 0 ).

"Optional matches
"#c #bc #bbc # #c
string_quan_rep_alt = replace( val = `abc abbc abbbc a ac` pcre = `ab?` with = `#` occ = 0 ).

"Alternative matches
"#z#y#xdwevfu
string_quan_rep_alt = replace( val = `azbycxdwevfu` pcre = `a|b|c` with = `#` occ = 0 ).

"Capturing non-greedily (zero or more repetitions)
"a#cd a#ccccd a#
string_quan_rep_alt = replace( val = `abcd abccccd ab` pcre = `bc*?` with = `#` occ = 0 ).

"_defghxi
string_quan_rep_alt = replace( val = `abcxdefghxi` pcre = `\A.*?x` with = `_` ).

"Example to compare with greedy capturing
"_i
string_quan_rep_alt = replace( val = `abcxdefghxi` pcre = `\A.*x` with = `_` ).

"Capturing non-greedily (one or more repetitions)
"a#d a#cccd ab
string_quan_rep_alt = replace( val = `abcd abccccd ab` pcre = `bc+?` with = `#` occ = 0 ).

"Example to compare with greedy capturing
"a#d a#d ab
string_quan_rep_alt = replace( val = `abcd abccccd ab` pcre = `bc+` with = `#` occ = 0 ).

"#Hallo#
string_quan_rep_alt = replace( val = `<span>Hallo</span>` pcre = `<.+?>` with = `#` occ = 0 ).

⬆️ back to top

Character Sets and Ranges

ExpressionRepresentsExample RegexExample StringMatchesDoes not Match
[...]Character set, matches a single character present in the listb[iu]bit bat but betbit bat but betbit bat but bet
[x-y]Character range, matches a single character in the specified range, note that ranges may be locale-dependenta[a-c0-5]aa1 ab2 ba3 cac4 da56 a7aa1 ab2 ba3 cac4 da56 a7aa1 ab2 ba3 cac4 da56 a7
[^...]Negation, matches any single character not present in the list[^Ap]ABapB, aA, p
[^x-y]Negation, matches any single character not within the range[^A-Ca-c1-4]ABCDabcd123456D, d, 5, 6A, B, C, a, b, c, 1, 2, 3, 4

Examples:

DATA string_char_sets_ranges TYPE string.

"Defining a character set
"#t bat #t bet
string_char_sets_ranges = replace( val = `bit bat but bet` pcre = `b[iu]` with = `#` occ = 0 ).

"Defining a character range
"#1 #2 b# c#4 d#6 a7
string_char_sets_ranges = replace( val = `aa1 ab2 ba3 cac4 da56 a7` pcre = `a[a-c0-5]` with = `#` occ = 0 ).

"Matching any single character not present in the list
"A##p
string_char_sets_ranges = replace( val = `ABap` pcre = `[^Ap]` with = `#` occ = 0 ).

"Matching any single character not within the range
"ABC#abc#1234##
string_char_sets_ranges = replace( val = `ABCDabcd123456` pcre = `[^A-Ca-c1-4]` with = `#` occ = 0 ).

⬆️ back to top

Anchors and Positions

ExpressionRepresentsExample RegexExample StringMatchesDoes not Match
\AStart of a subject\A.abc defabc defabc def
^Start of a subject (particularly relevant in multi-line mode)^.See above and more details in the option setting section
\ZEnd of a subject.\Zabc defabc defabc def
$End of a subject (particularly relevant in multi-line mode).$See above and more details in the option setting section
\bStart or end of word1. \ba.
2. \Dd\b
3. \b.d\b
abcd a12d ed1. abcd a12d ed
2. abcd a12d ed
3. abcd a12d ed
1. abcd a12d ed
2. abcd a12d ed
3. abcd a12d ed
\BNegation of \b, not at the start or end of words\Be\Bsee an elefantsee an elefantsee an elefant
\KResets the starting point of a match, i.e. findings are excluded from the final matcha.\Kcabcdabcdabcd

Examples:

DATA string_anchors_pos TYPE string.

"Start of subject, syntax \A
"#abc def
string_anchors_pos = replace( val = `abc def` pcre = `\A` with = `#` occ = 0 ).

"Start of subject, syntax ^; find more information below regarding multi-line mode
"#abc
"#def
"#ghi
string_anchors_pos = replace( val = |abc\ndef\nghi| pcre = `(?m)^` with = `#` occ = 0 ).

"The following examples uses ^ without enabling the multi-line mode
"#abc
"def
"ghi
string_anchors_pos = replace( val = |abc\ndef\nghi| pcre = `^` with = `#` occ = 0 ).

"End of subject, syntax \Z
"abc def#
string_anchors_pos = replace( val = `abc def` pcre = `\Z` with = `#` occ = 0 ).

"End of subject, syntax $
"The example uses multi-line mode
"abc#
"def#
"ghi#
string_anchors_pos = replace( val = |abc\ndef\nghi| pcre = `(?m)$` with = `#` occ = 0 ).

"Start or end of word
"#cd #2d ed
string_anchors_pos = replace( val = `abcd a12d ed` pcre = `\ba.` with = `#` occ = 0 ).

"ab# a12d #
string_anchors_pos = replace( val = `abcd a12d ed` pcre = `\Dd\b` with = `#` occ = 0 ).

"abcd a12d #
string_anchors_pos = replace( val = `abcd a12d ed` pcre = `\b.d\b` with = `#` occ = 0 ).

"Not at the start or end of words
"s#e an el#fant
string_anchors_pos = replace( val = `see an elefant` pcre = `\Be\B` with = `#` occ = 0 ).

"Resetting the starting point of a match
"ab#d
string_anchors_pos = replace( val = `abcd` pcre = `a.\Kc` with = `#` occ = 0 ).

⬆️ back to top

Capturing Groups, Replacements and Backreferences

ExpressionRepresentsExample RegexExample StringMatchesDoes not Match
(...)Capturing group to group parts of patterns together`b(a\u)t`bit bat but betbat, butbit, bet
(?<name>...), (?'name'...)Named capturing group(?<x>..)(?'y'..)abcd$x refers to ab, $y to cd
The reference can also be made using curly brackets: ${x}, ${y}
$x refers to cd, $y to ab
$id, ${id}Represents the substitute for a capturing group, id stands for a number or name of a capturing group(..)(..)abcd$1 refers to ab, $2 to cd
$0 refers to the content of the whole match
As above, the reference can also be made using curly brackets: ${0}, ${1}, ${2}
$1 refers to cd, $2 to ab
(?:...)Creates a group but it is not captured(?:ab)(ap)abapIt matches abap, but in a replacement and when referring to the subgroup $1, it refers to ap.ab
\1Backreference, refers to a previous capturing group; 1 represents the number of the group index (the group index starts with 1); more back reference syntax options are possible such as the specification of named groups(a.)(\w*)\1abcdefabghijabcdefabghij
Note: Capturing group 1 holds ab in the example. The second capturing group captures all word characters until ab is found.
abcdefabghij

Examples:

DATA string_capt_group TYPE string.

"bit # # bet
string_capt_group = replace( val = `bit bat but bet` pcre = `b(a|u)t` with = `#` occ = 0 ).

"------- Replacements with capturing groups -------

"ABAP
string_capt_group = replace( val = `APAB` pcre = `(..)(..)` with = `$2$1` ).

"$0 representing the content of the whole match
"#abcd#
string_capt_group = replace( val = `abcd` pcre = `(..)(..)` with = `#$0#` ).

"Alternative replacement syntax with the curly brackets
"ABAP
string_capt_group = replace( val = `APAB` pcre = `(..)(..)` with = `${2}${1}` ).

"------- Named capturing groups -------


"PCRE syntax (?<name>...), replacement syntax $name
"Examplatory result: Day: 28, month: 11, year: 2024
string_capt_group = replace( val = xco_cp=>sy->date( )->as( xco_cp_time=>format->abap )->value
                              pcre = `(?<yr>\d{4})(?<mo>\d{2})(?<d>\d{2})`
                              with = `Day: $d, month: $mo, year: $yr` ).


"Alternative PCRE syntax (?'name'...), replacement syntax ${name}
"Examplatory result: 28.11.2024
string_capt_group = replace( val = xco_cp=>sy->date( )->as( xco_cp_time=>format->abap )->value
                              pcre = `(?'yr'\d{4})(?'mo'\d{2})(?'d'\d{2})`
                              with = `${d}.${mo}.${yr}` ).

"Creating a group but not capturing it
"#cd#
string_capt_group = replace( val = `abcd` pcre = `(?:..)(..)` with = `#$1#` ).

"The following example raises an exception. $2 cannot be referred to.
TRY.
    string_capt_group = replace( val = `abcd` pcre = `(?:..)(..)` with = `#$1#$2#` ).
  CATCH cx_sy_invalid_regex_format.
ENDTRY.

"#abcd#
string_capt_group = replace( val = `abcd` pcre = `(?:..)(..)` with = `#$0#` ).

"------- Back reference -------

"In the example, the capturing group 1 holds `ab`. The second capturing group captures
"all word characters until `ab` is found, including `ab`. The reference to the first
"capturing group is made using \1.
"#ghij
string_capt_group = replace( val = `abcdefabghij` pcre = `(a.)(\w*)\1` with = `#` ).

⬆️ back to top

Lookarounds

ExpressionRepresentsExample RegexExample StringMatchesDoes not Match
(?=...)Positive lookahead, returns characters that are followed by a specified pattern without including this patterna(?=b)abc adeabc adeabc ade
(?!...)Negative lookahead, returns characters that are not followed by a specified pattern without including this patterna(?!b)abc adeabc adeabc ade
(?<=...)Positive lookbehind, returns characters that are preceded by a specified pattern without including this pattern(?<=\s)cab c abcdab c abcd (it is preceded by a blank)ab c abcd
(?<!...)Negative lookbehind, returns characters that are not preceded by a specified pattern without including this pattern(?<!\s)cab c abcdab c abcd (it is not preceded by a blank)ab c abcd

Examples:

DATA string_look_arounds TYPE string.

"Positive lookahead
"#bc ade
string_look_arounds = replace( val = `abc ade` pcre = `a(?=b)` with = `#` occ = 0 ).

"Negative lookahead
"abc #de
string_look_arounds = replace( val = `abc ade` pcre = `a(?!b)` with = `#` occ = 0 ).

"Positive lookbehind
"ab # abcd
string_look_arounds = replace( val = `ab c abcd` pcre = `(?<=\s)c` with = `#` occ = 0 ).

"Negative lookbehind
"ab c ab#d
string_look_arounds = replace( val = `ab c abcd` pcre = `(?<!\s)c` with = `#` occ = 0 ).

⬆️ back to top

Case Conversions in Replacement Patterns

You can use the following syntax options for case conversion in replacement patterns:

Examples:

DATA string_case_conv TYPE string.

"\u syntax
"abcDefg
string_case_conv = replace( val = `abcdefg` pcre = `c(.*)` with = `c\u$1` ).

"\U syntax
"abcDEFG
string_case_conv = replace( val = `abcdefg` pcre = `c(.*)` with = `c\U$1` ).

"\l syntax
"HIJKlMNO
string_case_conv = replace( val = `HIJKLMNO` pcre = `K(.*)` with = `K\l$1` ).

"\L syntax
"HIJKlmno
string_case_conv = replace( val = `HIJKLMNO` pcre = `K(.*)` with = `K\L$1` ).

"\E syntax
"abcDEfg
string_case_conv = replace( val = `abcdefg` pcre = `c(..)(..)` with = `c\U$1\E$2` ).

"The following example is a comparison to similar syntax without specifying \E
"abcDEFG
string_case_conv = replace( val = `abcdefg` pcre = `c(..)(..)` with = `c\U$1$2` ).

⬆️ back to top

Setting Options and Control Verbs

There are various setting options for specifying PCRE syntax. The following examples demonstrate a selection:

Multi- and single-line modes

Examples:

DATA string_opt_set TYPE string.

"----------- Examples with `.` and single line mode -----------

"`.` matches new lines feeds when the single line option is set
"Result (9 replacements):
"###
"###
"###
string_opt_set = replace( val = |abc\ndef\nghi| pcre = `.` with = `#` occ = 0 ).

"Result (11 replacements including the new line feeds):
"###########
string_opt_set = replace( val = |abc\ndef\nghi| pcre = `(?s).` with = `#` occ = 0 ).

"##
string_opt_set = replace( val = |\n\n| pcre = `(?s).` with = `#` occ = 0 ).

"----------- Examples for the start of subjects -----------

"Multi-line mode not enabled
"Result:
"#bc
"def
"ghi
string_opt_set = replace( val = |abc\ndef\nghi| pcre = `^.` with = `#` occ = 0 ).

"Multi-line mode enabled
"Result:
"#bc
"#ef
"#hi
string_opt_set = replace( val = |abc\ndef\nghi| pcre = `(?m)^.` with = `#` occ = 0 ).

"\A for comparison
"Result:
"#bc
"def
"ghi
string_opt_set = replace( val = |abc\ndef\nghi| pcre = `(?m)\A.` with = `#` occ = 0 ).

"----------- Examples for the end of subjects -----------

"Result:
"abc
"def
"gh#
string_opt_set = replace( val = |abc\ndef\nghi| pcre = `.$` with = `#` occ = 0 ).

"Result:
"ab#
"de#
"gh#
string_opt_set = replace( val = |abc\ndef\nghi| pcre = `(?m).$` with = `#` occ = 0 ).

"\Z syntax (the result is the same as with `.$`)
string_opt_set = replace( val = |abc\ndef\nghi| pcre = `(?m).\Z` with = `#` occ = 0 ).

Extended Mode

The following code snippet shows the extended mode enabled by default and then explicitly disabled in a PCRE regular expression.

DATA some_string TYPE string.

"Extended mode is enabled by default
"No replacement in the example.
"Result: abc def
some_string = replace( val = `abc def` pcre = `abc def` with = `#` ).

"The following example works because there is no whitespace in the source string.
"The whitespace in the regular expression is ignored.
"Result: #
some_string = replace( val = `abcdef` pcre = `abc def` with = `#` ).

"To match whitespace characters, you can use the pattern \s
"Result: #
some_string = replace( val = `abc def` pcre = `abc\sdef` with = `#` ).

"Escaping a whitespace using \
"Result: #
some_string = replace( val = `abc def` pcre = `abc\ def` with = `#` ).
"The following example also performs the replacement as the unescaped whitespaces
"are ignored.
some_string = replace( val = `abc def` pcre = `abc\         def` with = `#` ).

"Disabling the extended mode so that whitespaces are not ignored
"Result: #
some_string = replace( val = `abc def` pcre = `(?-x)abc def` with = `#` ).

Control verbs

Control verbs, for example, for ...

DATA ctrl_verb_string TYPE string.

"Using (*UTF); the source string contains a non-breakable space that is to be replaced
"Result: #x#
ctrl_verb_string = replace( 
  val = |#{ cl_abap_conv_codepage=>create_in( codepage = `UTF-16BE` )->convert( source = CONV xstring( `00A0` ) ) }#|
  pcre = `(*UTF)\N{U+00A0}` with = `x` occ = 0 ).

"Line breaks
"The results are demonstrated using string templates.
"In the examples, the multi-line mode is enabled in addition.

"|_abc\ndef\r_ghi\r_\njkl|
ctrl_verb_string = replace( val = |abc\ndef\rghi\r\njkl|
                            pcre = `(*CR)(?m)^` with = `_` occ = 0 ).

ctrl_verb_string = replace( val = |abc\ndef\rghi\r\njkl|
                            pcre = `(*LF)(?m)^` with = `_` occ = 0 ).

"|_abc\n_def\rghi\r\n_jkl|
ctrl_verb_string = replace( val = |abc\ndef\rghi\r\njkl|
                            pcre = `(*CRLF)(?m)^` with = `_` occ = 0 ).

"|_abc\n_def\r_ghi\r\n_jkl|
ctrl_verb_string = replace( val = |abc\ndef\rghi\r\njkl|
                            pcre = `(*ANYCRLF)(?m)^` with = `_` occ = 0 ).

⬆️ back to top

Callouts

The following example shows how to use callouts to call an ABAP method from a PCRE regular expression. It creates an object-oriented representation of a PCRE regex using the CL_ABAP_REGEX class, applying different PCRE syntaxes for callout specifications. The class implements the IF_ABAP_MATCHER_CALLOUT interface, and the callout method uses a demo class instance as the callout handler. If the regex matches, the method is called for each callout position. The callout method populates a string table with accessible details. This demonstrates that regex processing can be influenced, and in the example, processing stops when a condition is met. As a result, found is false because the regex is not fully processed. For more details, refer to the class documentation.

To try the example out, create a demo class named zcl_demo_abap and paste the code into it. After activation, choose F9 in ADT to execute the class. The example is set up to display output in the console.

CLASS zcl_demo_abap DEFINITION
  PUBLIC
  FINAL
  CREATE PUBLIC .

  PUBLIC SECTION.
    INTERFACES if_oo_adt_classrun.
    INTERFACES if_abap_matcher_callout.
  PROTECTED SECTION.
  PRIVATE SECTION.
    CLASS-DATA callout TYPE i.
    CLASS-DATA callout_tab TYPE string_table.
ENDCLASS.



CLASS zcl_demo_abap IMPLEMENTATION.

  METHOD if_oo_adt_classrun~main.
    DATA(text_to_search) = `abcdefghijklmnopq`.
    DATA(regex) = cl_abap_regex=>create_pcre( pattern = `(...)(?C1)(..)(?C2)(....)(?C3)(.)(?C"D")(....)(?C"E")(...)(?C"F")` ).
    DATA(matcher) = regex->create_matcher( text = text_to_search ).
    DATA(handler) = NEW zcl_demo_abap( ).
    matcher->set_callout( handler ).
    DATA(found) = matcher->match( ).

    IF found = abap_false.
      out->write( |Pattern not found.\n\n| ).
    ENDIF.

    out->write( callout_tab ).

  ENDMETHOD.

  METHOD if_abap_matcher_callout~callout.
    DATA(ts) = utclong_current( ).
    callout += 1.

    IF callout_string = `F`.
      callout_result = if_abap_matcher_callout=>c_callout_result-abort.
    ELSE.
      callout_result = if_abap_matcher_callout=>c_callout_result-pass.

      APPEND INITIAL LINE TO callout_tab.
      APPEND |----------------- Callout { callout } -----------------| TO callout_tab.
      APPEND INITIAL LINE TO callout_tab.
      APPEND |callout_num: { callout_num }| TO callout_tab.
      APPEND |callout_string: { callout_string }| TO callout_tab.
      APPEND |regex: { regex  }| TO callout_tab.
      APPEND |subject: { subject }| TO callout_tab.
      APPEND |current_subject_pos: { current_subject_pos }| TO callout_tab.
      APPEND |current_pattern_pos: { current_pattern_pos }| TO callout_tab.
      APPEND |capture_last: { capture_last }| TO callout_tab.
      APPEND |capture_last_len: { capture_last_len }| TO callout_tab.
      APPEND |capture_last_off: { capture_last_off }| TO callout_tab.
      APPEND |start_match_off: { start_match_off }| TO callout_tab.

      TRY.
          APPEND |Content of submatch: { subject+capture_last_off(capture_last_len) }| TO callout_tab.
        CATCH cx_sy_range_out_of_bounds.
      ENDTRY.
      APPEND |This callout was called at { ts }| TO callout_tab.
    ENDIF.

  ENDMETHOD.

ENDCLASS.

⬆️ back to top

Conditional Patterns

DATA string_cond_pattern TYPE string.

"------- Conditions in the search pattern -------

"Example pattern:
"- The first capturing group matches a digit.
"- The '?' character specifies that the capturing group participates
"  in the match optionally.
"- A condition is specified, introduced by '(?...' and referring to
"  the first capturing group (the digit) indicated by 1.
"- If the condition is met, i.e. a digit is found, then the yes pattern
"  is applied ('.pdf'), which participates in the match.
"- If the condition is not met, i.e. a digit is not found, then the no
"  pattern is applied ('.md'), which participates in the match.
"- As a result, '2.pdf' and the two '.md' occurrences (also the one
"  without the digit) are replaced.

"1.txt,a.txt,#,b.pdf,3.gif,c.gif,4#,d#,5.jpg,e.jpg
string_cond_pattern = replace( val = `1.txt,a.txt,2.pdf,b.pdf,3.gif,c.gif,4.md,d.md,5.jpg,e.jpg`
                                pcre = `(\d)?(?(1)\.pdf|\.md)` with = `#` occ = 0 ).

"------- Conditions in the replacement pattern -------

"Search pattern:
"- The '?' character specifies that the capturing group participates in the match optionally.
"Replacements pattern:
"- '$' followed by the specification of the capturing group that is referred to in curly brackets
"- The capturing group number is followed by a ':' and '+...' that denotes the value if true,
"  the value following the other colon denotes the value if false

"This is very good.
string_cond_pattern = replace( val = `correct`   pcre = `(in)?correct` with = `This is ${1:+not:very} good.` ).

"This is not good.
string_cond_pattern = replace( val = `incorrect` pcre = `(in)?correct` with = `This is ${1:+not:very} good.` ).

"Syntax {n:-default}
"Shortcut for the PCRE replacement pattern by specifying
"a default if the capture group does not participate in the match

"abcd
"'ab' participates in the match, so the default replacement pattern is not
"applied
string_cond_pattern = replace( val = `abcd` pcre = `(ab)?cd` with = `${1:-yz}cd` ).

"yzcd
"'ab' does not participate in the match, so the default replacement pattern is
"applied
string_cond_pattern = replace( val = `cd` pcre = `(ab)?cd` with = `${1:-yz}cd` ).

ABAP Statements Using Regular Expressions

The following example demonstrates a selection of syntax options with FIND and REPLACE. There are multiple options as there is a rich variety of additions. For more details, refer to the String Processing cheat sheet.

*&---------------------------------------------------------------------*
*& FIND
*&---------------------------------------------------------------------*

DATA(str) = `Cathy's black cat on the mat played with Matt.`.

"----- ALL OCCURRENCES addition: Finding all occurrences -----
"The MATCH COUNT addition stores the number of occurrences in a data object.

"Determining the number of letters in a string
"a: 36
FIND ALL OCCURRENCES OF PCRE `[A-Za-z]` IN str MATCH COUNT DATA(a).

"----- RESULTS addition: Finding all occurrences -----
"The example also uses the ALL OCCURRENCES addition. The findings are
"stored in a table of type match_result_tab.
FIND ALL OCCURRENCES OF PCRE `\s` IN str RESULTS DATA(b).

*LINE    OFFSET    LENGTH    SUBMATCHES
*0       7         1         OFFSET     LENGTH
*
*0       13        1         OFFSET     LENGTH
*
*0       17        1         OFFSET     LENGTH
*
*0       20        1         OFFSET     LENGTH
*
*0       24        1         OFFSET     LENGTH
*
*0       28        1         OFFSET     LENGTH
*
*0       35        1         OFFSET     LENGTH
*
*0       40        1         OFFSET     LENGTH

"----- SUBMATCHES addition: Storing capturing group content in variables -----
"Pattern: anything before and after ' on '
FIND PCRE `(.*)\son\s(.*)` IN str IGNORING CASE SUBMATCHES DATA(c) DATA(d).
"a: 'Cathy's black cat' / b: 'the mat played with Matt.'.

"Using the RESULTS addition to get offset and length information of
"all capturing groups, among others
FIND PCRE `(.*)\son\s(.*)` IN str IGNORING CASE RESULTS DATA(e).

*LINE    OFFSET    LENGTH    SUBMATCHES
*0       0         46        OFFSET    LENGTH
*                            0         17
*                            21        25

"----- MATCH OFFSET/LENGTH additions -----
"The following examples find the last occurrence of a comma and the following content.
"\K denotes that the comma is excluded from the result. Using the offset and length
"values, the part of the string is extracted. The examples underscore that you can
"achieve the same thing differently with different PCRE syntax patterns (which also
"applies to ABAP demonstrated with the use of the substring function and specifying
"the syntax string+off(len) to extract the substring).

str = `abc,def,ghi,jkl,mno,pqr,stu,vwx,yz`.

"Negative lookahead
FIND PCRE `,(?!.*,)\K.*` IN str MATCH OFFSET DATA(off_a) MATCH LENGTH DATA(len_a).
"yz
DATA(content_a) = substring( val = str off = off_a len = len_a ).

"Positive lookahead
FIND PCRE `,(?=[^,]*$)\K.*` IN str MATCH OFFSET DATA(off_b) MATCH LENGTH DATA(len_b).
DATA(content_b) = str+off_b(len_b).

ASSERT content_a = `yz`.
ASSERT content_b = content_a.

"----- IN TABLE addition: Searching in internal tables  -----
"The internal table must have a character-like line type.

"Searching in an internal table and retrieving line, offset, length information
"The example only searches for the first occurrence. See another example below
"that uses the ALL OCCURRENCES and RESULTS additions.
DATA(itab) = VALUE string_table( ( `Cathy's black cat on the mat played with the friend of Matt.` ) ).
"Pattern: 't' at the beginning of a word followed by another character
"d: 1, e: 21, f: 2
FIND FIRST OCCURRENCE OF PCRE `\bt.` IN TABLE itab
  IGNORING CASE MATCH LINE DATA(f) MATCH OFFSET DATA(g) MATCH LENGTH DATA(h).

"----- Searching in internal tables  -----
"The RESULTS addition stores findings in an internal table of type match_result_tab when
"ALL OCCURRENCES is used.
"Submatches (i.e. length and offset values of the submatches) are stored in internal
"tables themselves. Therefore, the example uses nested loops and the substring function
"to retrieve the strings.

"The objective of the following example is to extract the content of the segments that
"are positioned within /.../ in a URL. The segments are stored in an internal table.
DATA(url) = `https://help.sap.com/docs/abap-cloud/abap-concepts/controlled-sap-luw/`.
DATA url_parts TYPE string_table.

FIND ALL OCCURRENCES OF PCRE `(?<=\/)([^\/]+)(?=\/)` IN url RESULTS DATA(res).

"Details on the regular expression:
"- Positive lookbehind (?<=\/) that determines that the content is preceded by `/`
"- Positive lookahead (?=\/) that determines that the content is followed by `/
"- ([^\/]+) in between determines that any sequence of characters that are not `/` are matched
"- The match is put in parentheses to store the submatch

LOOP AT res INTO DATA(finding).
  LOOP AT finding-submatches INTO DATA(sub).
    DATA(url_part) = substring( val = url off = sub-offset len = sub-length ).
    APPEND url_part TO url_parts.
  ENDLOOP.
ENDLOOP.

"The following statement uses nested iteration expressions with FOR instead of nested
"LOOP statements.
DATA(url_parts_for_loop) = VALUE string_table( FOR wa1 IN res
                                               FOR wa2 IN wa1-submatches
                                               ( substring( val = url off = wa2-offset len = wa2-length ) ) ).

ASSERT url_parts = url_parts_for_loop.
*Content:
*help.sap.com
*docs
*abap-cloud
*abap-concepts
*controlled-sap-luw

*&---------------------------------------------------------------------*
*& REPLACE
*&---------------------------------------------------------------------*

DATA(str_replace) = `ab apppc app`.
DATA(str_replace_copy) = str_replace.

"Changing the source field directly with a REPLACE statement; same as above
"pc app#ab a
REPLACE PCRE `(.*?)PP(.*)` IN str_replace WITH `$2#$1` IGNORING CASE.

str_replace = str_replace_copy.

"ALL OCCURRENCES addition
"ab#apppc#app
REPLACE ALL OCCURRENCES OF PCRE `\s` IN str_replace WITH `#`.

str_replace = str_replace_copy.

"ab a## a#
REPLACE ALL OCCURRENCES OF PCRE `p.` IN str_replace WITH `#`
  REPLACEMENT COUNT DATA(repl_cnt) "3
  RESULTS DATA(repl_res).
"repl_res:
"LINE    OFFSET    LENGTH
"0       4         1
"0       5         1
"0       8         1

DATA(str_table_original) = VALUE string_table( ( `a1bc2` ) ( `d3ef` ) ( `4ghi` ) ( `jkl` ) ).
DATA(str_table) = str_table_original.

"Replacing all occurrences in a table
"RESULTS addition: Storing information in an internal table of type repl_result_tab
REPLACE ALL OCCURRENCES OF PCRE `\d`
  IN TABLE str_table
  WITH `#`
  RESULTS DATA(res_table).

"str_table: a#bc# / d#ef / #ghi / jkl
"res_table:
"LINE    OFFSET    LENGTH
"1       1         1
"1       4         1
"2       1         1
"3       0         1

str_table = str_table_original.

"Replacing the first occurrence in a table
"RESULTS addition: Storing information in a structure of type repl_result
REPLACE FIRST OCCURRENCE OF PCRE `\d`
  IN TABLE str_table
  WITH `#`
  RESULTS DATA(res_structure).

"str_table: a#bc2 / d3ef / 4ghi / jkl
"res_structure:
"LINE  OFFSET  LENGTH
"1     1       1

str_table = str_table_original.

"Restricting the search range in an internal table
REPLACE ALL OCCURRENCES OF PCRE `\d`
  IN TABLE str_table
  FROM 1 TO 2
  WITH `#`.

"str_table: a#bc# / d#ef / 4ghi / jkl

str_table = str_table_original.

"Offsets can be optionally specified (also only the offset of start or end line possible)
REPLACE ALL OCCURRENCES OF PCRE `\d`
  IN TABLE str_table
  FROM 1 OFFSET 3 TO 2 OFFSET 2
  WITH `#`.

"str_table: a1bc# / d#ef / 4ghi / jkl

⬆️ back to top

Built-In Functions in ABAP Using Regular Expressions

Examples:

DATA(text) = `Pieces of cakes.`.

"---------------- find ----------------
"The find function searches for the subtexting specified and returns the offset

"15
DATA(find) = find( val = text pcre = `\.` ).

"---------------- find_end ----------------
"find_end returns the sum of the offset of the occurrence plus the length of the match

"7 (6 + 1)
DATA(find_end) = find_end( val = text pcre = `\s` ).

"---------------- count ----------------

"2
DATA(count_a)  = count( val = text pcre = `\s` ).

"16
DATA(count_b)  = count( val = text pcre = `.` ).

"---------------- match ----------------

"jon.doe@email.com
DATA(match_a) = match( val = `The email address is jon.doe@email.com.`
                        pcre = `\w+(\.\w+)*@(\w+\.)+(\w{2,4})` ).

"Find blank (without inlcuding it in the result indicated by \K) and
"the following 2 characters, second occurrence
"ad
DATA(match_b) = match( val = `The email address is jon.doe@email.com.`
                        pcre = `\s\K..`
                        occ = 2 ).

"---------------- replace ----------------
"Pieces#of cakes.
DATA(replace_a) = replace( val = text pcre = `\s` with = `#` ).

"Pieces of#cakes.
DATA(replace_b) = replace( val = text pcre = `\s` occ = 2 with = `#` ).

"---------------- substring_* ----------------

text = `Lorem ipsum dolor sit amet`.

"Extracting a substring ...
"... after a matching regular expression

"dolor sit amet
DATA(substring_after) = substring_after( val = text pcre = `\s` occ = 2 ).


"... before a matching regular expression
"Lorem ipsum
DATA(substring_before) = substring_before( val = text pcre = `\s` occ = 2 ).

"... from a matching regular expression on including the match
"' dolor sit amet'
DATA(substring_from) = substring_from( val = text pcre = `\s` occ = 2  ).

"... up to a matching regular expression including the match
"'Lorem ipsum '
DATA(substring_to) = substring_to( val = text pcre = `\s` occ = 2 ).

"---------------- Predicate functions: contains, matches ----------------
"The built-in functions 'contains' returns a truth value. In the following
"examples, the truth value is demonstrated using the xsdbool function.

"X
DATA(contains) = xsdbool( contains( val = `abc def` pcre = `\s`  ) ).

"The built-in functions 'matches' compares a search range of the textual argument
"with a regular expression.

"X
DATA(matches) = xsdbool( matches( val  = `jon.doe@email.com`
                                  pcre = `\w+(\.\w+)*@(\w+\.)+(\w{2,4})` ) ).

⬆️ back to top

Built-In Functions in ABAP SQL and CDS Using Regular Expressions

The following example demonstrates built-in functions using regular expressions in ABAP SQL. For more information on the built-in functions for ABAP CDS, refer to the ABAP Keyword Documentation. The example assumes that the ABAP cheat sheet repository has been imported into the system as it uses some of its repository objects.

"Populating demo database tables
zcl_demo_abap_aux=>fill_dbtabs( ).

SELECT SINGLE
  carrid,    "LH
  carrname,  "Lufthansa
  url,       "http://www.lufthansa.com

  "Checks if expression contains a PCRE expression;
  "case-sensitive by default (case_sensitive parameter can be specified)
  "Notes on the 1 = found, 0 = not found
  "1
  like_regexpr( pcre  = '\..',         "Period that is followed by any character
                value = url ) AS like_regex,

  "Searches a PCRE pattern, returns offset of match;
  "many optional parameters: occurrence, case_sensitive, start, group
  "21
  locate_regexpr( pcre = '\..',        "Period followed by any character
                  value = url,
                  occurrence = 2 )     "2nd occurrence in the string
                  AS locate_regexpr,

  "Searches a PCRE pattern, returns offset of match + 1;
  "many optional parameters: occurrence, case_sensitive, start, group
  "2
  locate_regexpr_after( pcre = '.',     "Any character
                        value = url,
                        occurrence = 1 ) AS locate_regexpr_after,

  "Counts all occurrences of found PCRE patterns
  "2
  occurrences_regexpr( pcre = '\..',    "Period that is followed by any character
                        value = url ) AS occ_regex,

  "Replaces a found PCRE expression;
  "more parameters possible: occurrence, case_sensitive, start
  "http://www#ufthansa#om
  replace_regexpr( pcre = '\..',        "Period that is followed by any character
                    value = url,
                    with = '#' ) AS replace_regex,

  "Searches for a PCRE expression and returns the matched substring
  "More parameters possible: occurrence, case_sensitive, start, group
  ".lu
  substring_regexpr( pcre = '\...', "Period that is followed by any two characters
                      value = url ) AS substring_regexpr

  FROM zdemo_abap_carr
  WHERE carrid = 'LH'
  INTO @DATA(builtin_func_regex).

⬆️ back to top

System Classes for Regular Expressions: CL_ABAP_REGEX and CL_ABAP_MATCHER

Examples:

"Example string
DATA(str) = `a1 # B2 ? cd . E3`.

"----------- Creating an instance of a regular expression -----------

"Creating an instance of a regular expression with PCRE syntax
"using cl_abap_regex

"Example pattern: Any-non digit followed by a digit
DATA(regex) = cl_abap_regex=>create_pcre( pattern = `\D\d`
                                          ignore_case = abap_true ).

"----------- Creating matchers -----------

"Two ways are possible (both ways return references of type
"ref to cl_abap_matcher):
"- create_matcher method of the cl_abap_regex class
"- create_pcre method of the cl_abap_matcher class
"Note that several importing parameters are available to enable
"further settings of the regular expression, e.g. ignoring the
"case, using the extended mode, etc. The examples pass a string
"to the 'text' parameter. You can also specify internal tables
"with the 'table' parameter and more.

"Creating a matcher using the create_matcher method of the cl_abap_regex class
DATA(matcher_1) = regex->create_matcher( text = str ).
"Creating a matcher in one go using method chaining
DATA(matcher_2) = cl_abap_regex=>create_pcre( pattern = `\D\d`
                                              ignore_case = abap_true
                                            )->create_matcher( text = str ).

"Creating a matcher using the create_pcre method of the cl_abap_matcher class
DATA(matcher_3) = cl_abap_matcher=>create_pcre( pattern = `\D\d`
                                                text    = str
                                                ignore_case = abap_true ).

"----------- Exploring searching and replacing -----------

"--- Finding all occurrences using the find_all method ---
"In the example, result has the type match_result_tab containing the findings.
DATA(result_fa1) = matcher_1->find_all( ).

*LINE    OFFSET    LENGTH    SUBMATCHES
*0       0         2         OFFSET     LENGTH
*
*0       5         2         OFFSET     LENGTH
*
*0       15        2         OFFSET     LENGTH

DATA(result_fa2) = matcher_2->find_all( ).
ASSERT result_fa2 = result_fa1.

"Getting the result in one go using method chaining with cl_abap_matcher
DATA(result_fa3) = cl_abap_matcher=>create_pcre( pattern = `\D\d`
                                                text    = str
                                                ignore_case = abap_true
                                              )->find_all( ).
ASSERT result_fa3 = result_fa1.

"--- Example with submatches ---

str = `XabcdXXefgXXhXXijklmnXX`.

DATA(result_fa4) = cl_abap_matcher=>create_pcre( pattern = `X(.*?)X`
                                                 text    = str
                                                 ignore_case = abap_true
                                               )->find_all( ).

*LINE    OFFSET    LENGTH    SUBMATCHES
*0       0         6         OFFSET    LENGTH
*                            1         4
*0       6         5         OFFSET    LENGTH
*                            7         3
*0       11        3         OFFSET    LENGTH
*                            12        1
*0       14        8         OFFSET    LENGTH
*                            15        6

"--- Replacing all occurrences using the 'replace_all' method ---

DATA(matcher_repl_1) = cl_abap_regex=>create_pcre( pattern = `X(.*?)X`
                                                 )->create_matcher( text = str ).

"4
DATA(repl_count_1) = matcher_repl_1->replace_all( newtext = `#$1#` ).

"#abcd##efg##h##ijklmn#X
DATA(repl_result_1) = matcher_repl_1->text.

"Using cl_abap_matcher
DATA(matcher_repl_2) = cl_abap_matcher=>create_pcre( pattern = `X(.*?)X`
                                                     text    = str ).
DATA(repl_count_2) = matcher_repl_2->replace_all( newtext = `#$1#` ).
DATA(repl_result_2) = matcher_repl_2->text.

"---- Sequential processing of the regular expression ---
"---- using the find_next method ------------------------
"The example explores various other methods, and writes
"information to a string table.

str = `a1bc2def3ghij45klm67opqr8stuvwx90yz`.

DATA(matcher_fn) = cl_abap_matcher=>create_pcre( pattern = `\d(\D.)`
                                                 text    = str ).

DATA strtab TYPE string_table.
WHILE matcher_fn->find_next( ) = abap_true.
  APPEND |---- Finding { sy-index } -----| TO strtab.

  "Type match_result
  DATA(match_result) = matcher_fn->get_match( ).

  DATA(offset) = matcher_fn->get_offset( ).
  DATA(length) = matcher_fn->get_length( ).
  DATA(matched_content) = str+offset(length).

  APPEND |Match offset: { offset }| TO strtab.
  APPEND |Match length: { length }| TO strtab.
  APPEND |Match content: { matched_content }| TO strtab.

  "Type match_result
  DATA(subgroup) = matcher_fn->get_match( )-submatches.

  LOOP AT subgroup INTO DATA(wa).
    DATA(sub_tabix) = sy-tabix.
    DATA(submatch_line) = wa.
    DATA(submatch_offset) = wa-offset.
    DATA(submatch_length) = wa-length.
    DATA(submatch) = matcher_fn->get_submatch( sub_tabix ).
    APPEND |Submatch { sub_tabix } offset: { submatch_offset }| TO strtab.
    APPEND |Submatch { sub_tabix } length: { submatch_length }| TO strtab.
    APPEND |Submatch { sub_tabix } content: { submatch }| TO strtab.
  ENDLOOP.

ENDWHILE.

"---- Using an object of type cl_abap_regex in ABAP ---
"---- statements with the REGEX addition --------------

DATA(result_find_all_1) = cl_abap_matcher=>create_pcre( pattern = `\d(\D.)`
                                                        text = str
                                                      )->find_all( ).
DATA(result_find_all_2) = cl_abap_regex=>create_pcre( pattern = `\d(\D.)`
                                           )->create_matcher( text = str
                                           )->find_all( ).

DATA(reg_expr) = cl_abap_regex=>create_pcre( pattern = `\d(\D.)` ).

FIND ALL OCCURRENCES OF REGEX reg_expr IN str RESULTS DATA(result_find_all_3).

*LINE    OFFSET    LENGTH    SUBMATCHES
*0       1         3         OFFSET    LENGTH
*                            2         2
*0       4         3         OFFSET    LENGTH
*                            5         2
*0       8         3         OFFSET    LENGTH
*                            9         2
*0       14        3         OFFSET    LENGTH
*                            15        2
*0       19        3         OFFSET    LENGTH
*                            20        2
*0       24        3         OFFSET    LENGTH
*                            25        2
*0       32        3         OFFSET    LENGTH
*                            33        2

ASSERT result_find_all_3 = result_find_all_1.
ASSERT result_find_all_3 = result_find_all_2.

"Note that the REGEX addition is obsolete when using (POSIX) syntax patterns
"A syntax warning is displayed for the following example.
"FIND ALL OCCURRENCES OF REGEX `\d(\D.)` IN str RESULTS DATA(result_8).

"The syntax warning can be suppressed using a pragma
FIND ALL OCCURRENCES OF REGEX `\d(\D.)` IN str RESULTS DATA(result_find_all_4) ##REGEX_POSIX.

"Using PCRE instead
FIND ALL OCCURRENCES OF PCRE `\d(\D.)` IN str RESULTS DATA(result_find_all_5).
ASSERT result_find_all_5 = result_find_all_3.

"---------------- Exploring more parameters of the create_pcre method ----------------
"See the class documentation for more parameters and information.

"--- enable_multiline parameter ---

str = |abc\ndef\nghi\njkl|.

DATA(matcher_no_ml) = cl_abap_matcher=>create_pcre( pattern = `^`
                                                    text    = str ).
"1
DATA(repl_count_no_ml) = matcher_no_ml->replace_all( newtext = `#` ).
"|#abc\ndef\nghi\njkl|
DATA(repl_result_no_ml) = matcher_no_ml->text.

DATA(matcher_w_ml) = cl_abap_matcher=>create_pcre( pattern = `^`
                                                   text    = str
                                                   enable_multiline = abap_true ).
"4
DATA(repl_count_w_ml) = matcher_w_ml->replace_all( newtext = `#` ).
"|#abc\n#def\n#ghi\n#jkl|
DATA(repl_result_w_ml) = matcher_w_ml->text.

"--- table/ignore_case parameters ---

data(str_table) = VALUE string_table( ( `abZdez` ) ( `zZfghZ` ) ( `ijkZZz` ) ( `zzzzZ` ) ).

DATA(matcher_tab) = cl_abap_matcher=>create_pcre( pattern = `z+`
                                                  table   = str_table
                                                  ignore_case = abap_true ).
"6
DATA(repl_count_tab) = matcher_tab->replace_all( newtext = `#` ).
"ab#de# / #fgh# / ijk# / #
DATA(repl_result_tab) = matcher_tab->table.

"--- extended parameter ---

str = `abc def`.

DATA(matcher_w_extended) = cl_abap_matcher=>create_pcre( pattern = `abc def`
                                                         text    = str ).

"No replacement in the following example as the extended mode is
"enabled by default.
"0
DATA(repl_count_w_extended) = matcher_w_extended->replace_all( newtext = `#` ).
"abc def
DATA(repl_result_w_extended) = matcher_w_extended->text.

"Disabling the extended mode so that whitespaces are not ignored
DATA(matcher_not_extended) = cl_abap_matcher=>create_pcre( pattern = `abc def`
                                                           text    = str
                                                           extended = abap_false ).

"1
DATA(repl_count_not_extended) = matcher_not_extended->replace_all( newtext = `#` ).
"#
DATA(repl_result_not_extended) = matcher_not_extended->text.

⬆️ back to top

Executable Example

zcl_demo_abap_regex

[!NOTE] - The executable example of the String Processing cheat sheet also includes examples with regular expressions. - The steps to import and run the code are outlined here. - Disclaimer
来源说明:本节内容来源:SAP-samples/abap-cheat-sheets (GitHub),原作者 SAP。原 Markdown 文件:28_Regular_Expressions.md。版权归原作者所有。