当前位置: 代码迷 >> SAP >> [SAP ABAP开发技术小结]字符串处理函数、正则表达式
  详细解决方案

[SAP ABAP开发技术小结]字符串处理函数、正则表达式

热度:315   发布时间:2016-04-29 01:47:05.0
[SAP ABAP开发技术总结]字符串处理函数、正则表达式

声明:原创作品转载时请注明文章来自SAP师太博客并以超链接形式标明文章原始出处否则将追究法律责任!
原文出自:
字符串处理是每门应用语言里都要掌握的,在SAP ABAP语言里也不例外,说到字符串处理,必然少不了正则式的出现,有了正则式,字符串才可以灵活处理,不过我在ABAP项目中看到的还都是使用的以前R3中老式的字符串处理语句。这节的内容是非常重要的,学好后,多复杂的字符串处理也不在话下。如果你以前学过其他语言正则式,比如Java中的正则式,这节内容看得就很轻松了。当然,正则式不是哪门语言特有的,正则式有如数据结构一样,只是使用不同语言去实现他而已,就是我一样,以前研究过Java中的正则式,然后在JavaScript中一样,最后到ABAP中,精髓还是一样,只是语句不同而已!

1.7.  字符串处理常用函数

SPLIT dobj AT sep INTO { {result1 result2 ...} | {TABLE result_tab} }必须指定足够目标字段。否则,用字段dobj的剩余部分填充最后目标字段并包含分界符;或者使用内表动态接收

SHIFT dobj {[{BY num PLACES}|{UP TO sub_string}][[LEFT|RIGHT][CIRCULAR]]}
           | { 
{LEFT DELETING LEADING}|{RIGHT DELETING TRAILING
} } pattern

对于固定长度字符串类型,shift产生的空位会使用空格或十六进制的0(如果为X类型串时)来填充

向右移动时前面会补空格,固定长度类型字符串与String结果是不一样:String类型右移后不会被截断,只是字串前面补相应数量的空格,但如果是C类型时,则会截断;左移后后面是否被空格要看是否是固定长度类型的字符串还是变长的String类型串,左移后C类型会补空格,String类型串不会(会缩短)

CIRCULAR:将移出的字符串放在左边或者左边

pattern:只要前导或尾部字符在指定的pattern字符集里就会被去掉,直到第一个不在模式pattern的字符止

CONDENSE <c> [NO-GAPS].如果是C类型只去掉前面的空格(因为是定长,即使后面空格去掉了,左对齐时后面会补上空格),如果是String类型,则后面空格也会被去掉;字符串中间的多个连续的空格使用一个空格替换(String类型也是这样)NO-GAPS:字符串中间的所有空格都也都会去除(String类型也是这样);空格去掉后会左对齐[k?n?dens] 

CONCATENATE {dobj1 dobj2 ...}|{LINES OF itab}[k?n?kat?ne?t]
            INTO result
            [
SEPARATED BY
sep]
            [
RESPECTING BLANKS]
.

CDNT类型的前导空格会保留,尾部空格都会被去掉,但对String类型所有空格都会保留;对于c, d, n, t类型的字符串有一个RESPECTING BLANKS选项可使用,表示尾部空格也会保留。注:使用 `` String类型进行赋值时才会保留尾部空格  字符串连接可以使用 && 来操作,具体请参考这里

strlen(arg)Xstrlen(arg)String类型的尾部空格会计入字符个数中,但C类型的变量尾部空格不会计算入

substring( val = TEXT [off = off] [len = len] )

count( val = TEXT {sub = substring}|{regex = regex} )匹配指定字符串substring或正则式regex出现的子串次数,返回的类型为i整型类型

contains( val = TEXT REGEX = REGEX)是否包含。返回布尔值,注:只能用在ifWhile等条件表达式中

matches( val = TEXT REGEX = REGEX)regex表达式要与text完全匹配,这与contains是不一样的。返回布尔值,也只能用在ifWhile等条件表达式中

match( val = TEXT REGEX = REGEX occ = occ)返回的为匹配到的字符串。注:每次只匹配一个。occ:表示需匹配到第几次出现的子串。如果为正,则从头往后开始计算,如果为负,则从尾部向前计算

find( val = TEXT {sub = substring}|{regex = regex}[occ = occ] )查找substring或者匹配regex的子串的位置。如果未找到,则返回 -1,返回的为offset,所以从0开始

FIND ALL OCCURRENCES OF REGEX regex IN  dobj
  [
MATCH COUNT 
mcnt]
  成功匹配的次数
  { {[MATCH OFFSET moff][MATCH LENGTH mlen]}最后一次整体匹配到的串(整体串,最外层分组,而不是指正则式最内最后一个分组)起始位置与长度
  | [RESULTS result_tab|result_wa] } result_tab接收所有匹配结果,result_wa只能接收最后一次匹配结果
  [SUBMATCHES s1 s2 ...].
通常与前面的MATCH OFFSET/ LENGTH一起使用。只会接收使用括号进行分组的子组。如果变量s1 s2 ...比分组的数量多,则多余的变量被initial;如果变量s1 s2 ...比分组的数量少,则多余的分组将被忽略;且只存储第一次或最后一次匹配到的结果

replace( val = TEXT  REGEX = REGEX  WITH = NEW)使用new替换指定的子符串,返回String类型

REPLACE ALL OCCURRENCES OF REGEX regex IN  dobj WITH new

1.7.1.   countmatch结合

DATA: text TYPE string VALUE `Cathy's cat with the hat sat on Matt's mat.`,
      regx
TYPE string VALUE `\<.at\>`."\< 单词开头\> 单词结尾
DATA: counts TYPE i,
     
index TYPE i,
      substr
TYPE string.
WRITE / text.
NEW-LINE.
counts
= count( val = text regex = regx )."返回匹配次数
DO counts TIMES.
 
index = find( val   = text regex = regx occ = sy-index )."返回匹配到的的起始位置索引
  substr
= match( val  = text regex = regx occ = sy-index )."返回匹配到的串
 
index = index + 1.
 
WRITE AT index substr.
ENDDO.

image013

1.7.2.   FIND …SUBMATCHES 

DATA: moff TYPE i,
       mlen
TYPE i,
       s1  
TYPE string,
       s2  
TYPE string,
       s3  
TYPE string,
       s4  
TYPE string.
FIND ALL OCCURRENCES OF REGEX `((\w+)\W+\2\W+(\w+)\W+\3)`"\2 \3 表示反向引用前面匹配到的第二与第三个子串
    
IN `Hey hey, my my, Rock and roll can never die Hey hey, my my`"会匹配二次,但只会返回第二次匹配到的结果,第一次匹配到的子串不会存储到s1s2s3中去
    
IGNORING CASE
    
MATCH OFFSET moff
   
MATCH LENGTH
mlen
    
SUBMATCHES s1 s2 s3 s4."
根据从外到内,从左到右的括号顺序依次存储到s1 s2…中,注:只取出使用括号括起来的子串,如想取整体子串则也要括起来,这与Java不同
WRITE: /  s1, / s2,/ s3 ,/ s4,/ moff ,/ mlen."s4
会被忽略

image014

1.7.3.   FIND …RESULTS  itab

DATA: result TYPE STANDARD TABLE OF string WITH HEADER LINE .
 
"Java不同,只要是括号括起来的都称为子匹配(即使用整体也用括号括起来了),
 
"不管括号嵌套多少层,统称为子匹配,且匹配到的所有子串都会存储到,
 
"MATCH_RESULT-SUBMATCHES中,即使最外层的括号匹配到的子串也会存储到SUBMATCHES
 
"
内表中。括号解析的顺序为:从外到内,从左到右的优先级顺序来解析匹配结构。
 
"Java中的group(0)存储的是整体匹配串,即使整体未(或使用)使用括号括起来
 
PERFORM get_match TABLES result
         
USING '2011092131221032' '(((\d{2})(\d{2}))(\d{2})(\d{2}))'.

 
LOOP AT result .
   
WRITE: / result.
 
ENDLOOP.
FORM get_match  TABLES p_result"返回所有分组匹配(括号括起来的表达式)
               
USING    p_str
                         p_reg
.

 
DATA: result_tab TYPE match_result_tab WITH HEADER LINE.
 
DATA: subresult_tab TYPE submatch_result_tab WITH HEADER LINE.
 
"注意:带表头时 result_tab 后面一定要带上中括号,否则激活时出现奇怪的问题

 
FIND ALL OCCURRENCES OF REGEX p_reg IN p_str RESULTS result_tab[].
 
"result_tab中存储了匹配到的子串本身(与Regex整体匹配的串,存储在
 
"result_tab-offsetresult_tab-length中)以及所子分组(括号部分,存储在
 
"result_tab-submatches中)
 
LOOP AT result_tab .
   
"如需取整体匹配到的子串(与Regex整体匹配的串),则使用括号将整体Regex括起来
   
"来即可,括起来后也会自动存储到result_tab-submatches,而不需要在这里像这样读取
*    p_result = p_str+result_tab-offset(result_tab-length).
*    APPEND p_result.
    subresult_tab[]
= result_tab-submatches.
   
LOOP AT subresult_tab.
      p_result
= p_str+subresult_tab-offset(subresult_tab-length).
     
APPEND p_result.
   
ENDLOOP.
 
ENDLOOP.
ENDFORM.

image015 image016

1.7.4.   正则式类

regex = Regular expression   [?reɡjul?]

cl_abap_regexJava中的 java.util.regex.Pattern的类对应

cl_abap_matcherJava中的 java.util.regex.Matcher的类对应

1.7.4.1.            matchesmatch

是否完全匹配正则式中不必使用 ^ $);matches为静态方法match为实例方法作用都是一样

DATA: matcher TYPE REF TO cl_abap_matcher,
      match
TYPE match_result,
      match_line
TYPE submatch_result.
"^$可以省略因为matches方法本身就是完全匹配整个Regex
IF cl_abap_matcher
=>matches( pattern = '^(db(ai).*)$' text = 'dbaiabd' ) = 'X'.
  matcher
= cl_abap_matcher
=>get_object( )."获取最后一次匹配到的 Matcher 实例
  match
= matcher
->get_match( ). "获取最近一次匹配的结果(是整体匹配的结果)
 
WRITE / matcher->text+match-offset(match-length).
 
LOOP AT  match-submatches INTO match_line. "提取子分组括号括起来的部分
   
WRITE: /20 match_line-offset, match_line-length,matcher->text+match_line-offset(match_line-length).
 
ENDLOOP.
ENDIF.

image017

DATA: matcher TYPE REF TO cl_abap_matcher,
      match
TYPE match_result,
      match_line
TYPE submatch_result.
"^$可以省略,因为matche方法本身就是完全匹配整个Regex
matcher
= cl_abap_matcher
=>create( pattern = '^(db(ai).*)$' text = 'dbaiabd' ).
IF matcher
->match(  ) = 'X'.
  match
= matcher
->get_match( ). "获取最近一次匹配的结果
 
WRITE / matcher->text+match-offset(match-length).
 
LOOP AT  match-submatches INTO match_line. "提取子分组(括号括起来的部分)
   
WRITE: /20 match_line-offset, match_line-length,matcher->text+match_line-offset(match_line-length).
 
ENDLOOP.
ENDIF.

image018

1.7.4.2.            contains

是否包含也可在正则式中使用 ^ $ 用于完全匹配检查或者使用 ^ 检查是否匹配开头或者使用 $ 匹配结尾

DATA: matcher TYPE REF TO cl_abap_matcher,
      match
TYPE match_result,
      match_line
TYPE submatch_result.
IF cl_abap_matcher
=>contains( pattern = '(db(ai).{2}b)' text = 'dbaiabddbaiabb' ) = 'X'.
  matcher
= cl_abap_matcher
=>get_object( ). "获取最后一次匹配到的 Matcher 实例
  match
= matcher
->get_match( ). "获取最近一次匹配的结果
 
WRITE / matcher->text+match-offset(match-length).
 
LOOP AT  match-submatches INTO match_line. "提取子分组(括号括起来的部分)
   
WRITE: /20 match_line-offset, match_line-length,matcher->text+match_line-offset(match_line-length).
 
ENDLOOP.
ENDIF.

image019

1.7.4.3.            find_all

一次性找出所有匹配的子串,包括子分组(括号括起的部分)

DATA: matcher TYPE REF TO cl_abap_matcher,
       match_line
TYPE submatch_result,
      itab
TYPE match_result_tab WITH HEADER LINE.
matcher
= cl_abap_matcher
=>create( pattern = '<[^<>]*(ml)>' text = '<html>hello</html>' )."创建 matcher 实例
":子分组存储在itab-submatches字段里
itab[] = matcher
->find_all( ).
LOOP AT itab .
 
WRITE: / matcher->text, itab-offset, itab-length,matcher->text+itab-offset(itab-length).
  LOOP AT  itab-
submatches INTO match_line. "提取子分组(括号括起来的部分)
   
WRITE: /20 match_line-offset, match_line-length,matcher->text+match_line-offset(match_line-length).
 
ENDLOOP.
ENDLOOP.

image020

1.7.4.4.            find_next

逐个找出匹配的子串,包括子分组(括号括起的部分)

DATA: matcher TYPE REF TO cl_abap_matcher,
      match
TYPE match_result, match_line TYPE submatch_result,
      itab
TYPE match_result_tab WITH HEADER LINE.
matcher
= cl_abap_matcher
=>create( pattern = '<[^<>]*(ml)>' text = '<html>hello</html>' ).
WHILE matcher
->find_next( ) = 'X'.
  match
= matcher
->get_match( )."获取最近一次匹配的结果
 
WRITE: / matcher->text, match-offset, match-length,matcher->text+match-offset(match-length). 
  
LOOP AT  match-submatches INTO match_line. "提取子分组(括号括起来的部分)
    
WRITE: /20 match_line-offset, match_line-length,matcher->text+match_line-offset(match_line-length).
  ENDLOOP.
ENDWHILE.

image021

1.7.4.5.            get_lengthget_offsetget_submatch

DATA: matcher TYPE REF TO cl_abap_matcher,
      length
TYPE i,offset TYPE i,
      submatch
TYPE string.
matcher
= cl_abap_matcher
=>create( pattern = '(<[^<>]*(ml)>)' text = '<html>hello</html>' ).
WHILE matcher
->find_next( ) = 'X'. "循环2
 
"0时,表示取整个Regex匹配到的子串,这与Java一样,但如果整个Regex使用括号括起来后,
 
"则分组索引为1,这又与Java不一样(Java不管是否使用括号将整个Regex括起来,分组索引号都为0
  "
上面Regex中共有两个子分组,再加上整个Regex为隐含分组,所以一共为3
 
DO 3 TIMES.
   
"在当前匹配到的串(整个Regex相匹配的串)中返回指定子分组的匹配到的字符串长度
    length
= matcher
->get_length( sy-index - 1 ).
   
"在当前匹配到的串(整个Regex相匹配的串)中返回指定子分组的匹配到的字符串起始位置
    offset
= matcher
->get_offset( sy-index - 1 ).
   
"在当前匹配到的串(整个Regex相匹配的串)中返回指定子分组的匹配到的字符串
    submatch
= matcher
->get_submatch( sy-index - 1 ).
   
WRITE:/ length , offset,matcher->text+offset(length),submatch.
 
ENDDO.
 
SKIP.
ENDWHILE.

image022

1.7.4.6.            replace_all

DATA: matcher TYPE REF TO cl_abap_matcher,
      count
TYPE i,
      repstr
TYPE string.
matcher
= cl_abap_matcher=>create( pattern = '<[^<>]*>' text = '<html>hello</html>' ).
count
 = matcher
->replace_all( ``)."返回替换的次数
repstr
= matcher->text. "获取被替换后的新串
WRITE: / count , repstr.

image023

 
本站暂不开放注册!
内测阶段只得通过邀请码进行注册!
 
  • 最近登录:Tue Jul 25 00:43:49 CST 2017
  • 最近登录:Tue Jul 25 00:43:49 CST 2017
  • 最近登录:Tue Jul 25 00:43:49 CST 2017
  • 最近登录:Tue Jul 25 00:43:49 CST 2017
  • 最近登录:Tue Jul 25 00:43:49 CST 2017