1988 lines
72 KiB
ABAP
1988 lines
72 KiB
ABAP
***********************************************************************
|
|
*
|
|
* ABAP cheat sheet: String processing
|
|
*
|
|
* -------------------------- PURPOSE ----------------------------------
|
|
* - Example to demonstrate various syntax options for processing
|
|
* character strings.
|
|
* - Topics covered: Creating strings and assigning values, chaining strings,
|
|
* string templates, concatenating/splitting/modifying strings, searching
|
|
* and replacing, regular expressions
|
|
*
|
|
* ----------------------- GETTING STARTED -----------------------------
|
|
* - Open the class with the ABAP development tools for Eclipse (ADT).
|
|
* - Choose F9 to run the class.
|
|
* - Check the console output.
|
|
* - To understand the context and the ABAP syntax used, refer to the
|
|
* notes included in the class as comments or refer to the respective
|
|
* topic in the ABAP Keyword Documentation.
|
|
* - Due to the amount of console output, the examples contain numbers
|
|
* (e.g. 1) ..., 2) ..., 3) ...) for the individual example sections.
|
|
* Also, the variable name is displayed in most cases. So to find
|
|
* the relevant output in the console easier and faster, just search
|
|
* for the number/variable name in the console (CTRL+F in the console)
|
|
* or use the debugger.
|
|
*
|
|
* ----------------------------- NOTE -----------------------------------
|
|
* The code presented in this class is intended only to support the ABAP
|
|
* cheat sheets. It is not intended for direct use in a production system
|
|
* environment. The code examples in the ABAP cheat sheets are primarily
|
|
* intended to provide a better explanation and visualization of the
|
|
* syntax and semantics of ABAP statements, not to solve concrete
|
|
* programming tasks. For production application programs, you should
|
|
* always work out your own solution for each individual case. There is
|
|
* no guarantee for the correctness or completeness of the code.
|
|
* Furthermore, there is no legal responsibility or liability for any
|
|
* errors or their consequences that may occur when using the the example
|
|
* code.
|
|
*
|
|
***********************************************************************
|
|
"! <p class="shorttext synchronized">ABAP cheat sheet: String processing</p>
|
|
"! Example to demonstrate string processing.<br>Choose F9 in ADT to run the class.
|
|
CLASS zcl_demo_abap_string_proc DEFINITION
|
|
PUBLIC
|
|
FINAL
|
|
CREATE PUBLIC .
|
|
|
|
PUBLIC SECTION.
|
|
INTERFACES: if_oo_adt_classrun.
|
|
|
|
PROTECTED SECTION.
|
|
PRIVATE SECTION.
|
|
ENDCLASS.
|
|
|
|
|
|
|
|
CLASS zcl_demo_abap_string_proc IMPLEMENTATION.
|
|
|
|
|
|
METHOD if_oo_adt_classrun~main.
|
|
|
|
out->write( |ABAP Cheat Sheet Example: String Processing\n\n| ).
|
|
out->write( |1) Creating Strings and Assigning Values\n\n| ).
|
|
|
|
"Data object declarations providing default values
|
|
DATA: flag TYPE c LENGTH 1 VALUE 'X', "Single quotes
|
|
str_a1 TYPE string VALUE `Hallo, how are you?`. "Backquotes
|
|
|
|
DATA: char_a1 TYPE c LENGTH 5,
|
|
str_a2 TYPE string,
|
|
str_a3 LIKE str_a2.
|
|
|
|
"Examples for type n
|
|
DATA zip_code TYPE n LENGTH 5 VALUE '12345'.
|
|
|
|
DATA isbn_number TYPE n LENGTH 13 VALUE '1234567890123'.
|
|
|
|
"Value assignments to existing data objects
|
|
char_a1 = 'ab123'.
|
|
|
|
str_a2 = `<p>Hallo!</p>`.
|
|
|
|
"Escaping a backquote using another backquote
|
|
str_a3 = `This is a backquote: ``.`.
|
|
|
|
"If possible, avoid unnecessary type conversion; in principle,
|
|
"every convertible type can be specified
|
|
"Assigning a fixed-length string to a variable-length string.
|
|
str_a2 = 'abc'.
|
|
|
|
DATA str_a4 TYPE string VALUE 'X'. "Type c length 1
|
|
|
|
DATA str_a5 TYPE string VALUE -1. "Type i
|
|
|
|
"Inline declaration: data object declaration and
|
|
"value assignment
|
|
"Data type is automatically derived
|
|
DATA(char_a2) = 'abcd'. "Type c length 4
|
|
|
|
DATA(str_a6) = `efgh`. "Type string
|
|
|
|
"Note: Variable is of type c length 4. Characters are truncated.
|
|
char_a2 = 'ijklmnopq'.
|
|
|
|
"Treating trailing blanks
|
|
DATA(char_a3) = 'ab '.
|
|
|
|
DATA(str_a7) = `cdefgh`.
|
|
|
|
str_a7 = char_a3. "Trailing blanks are not respected.
|
|
|
|
"Excursion: Chaining strings
|
|
"Note the conversion result of str_a5 above (i to string)
|
|
DATA(str_a8) = str_a4 && ` ` && str_a5 && `!`.
|
|
|
|
out->write( data = str_a3 name = `str_a3` ).
|
|
out->write( |\n| ).
|
|
out->write( data = char_a2 name = `char_a2` ).
|
|
out->write( |\n| ).
|
|
out->write( data = str_a7 name = `str_a7` ).
|
|
out->write( |\n| ).
|
|
out->write( data = str_a8 name = `str_a8` ).
|
|
|
|
**********************************************************************
|
|
|
|
out->write( zcl_demo_abap_aux=>heading( `2) Chaining Strings` ) ).
|
|
|
|
DATA(str_b1) = `Hallo`.
|
|
DATA(str_b2) = `how`.
|
|
DATA(str_b3) = `are`.
|
|
|
|
"Chaining using && operator
|
|
DATA(str_b4) = str_b1 && ` ` && sy-uname && `, ` && str_b2 && ` ` && str_b3 && ` you?`.
|
|
|
|
"Chaining only character literals of the same type using & operator
|
|
"Note: Such a combination of literals is possible up to 255 chars.
|
|
DATA(char_b1) = 'AB' & 'AP '. "Trailing blanks are ignored
|
|
|
|
DATA(str_b5) = `AB` & `AP `.
|
|
|
|
out->write( data = str_b4 name = `str_b4` ).
|
|
out->write( |\n| ).
|
|
out->write( data = char_b1 name = `char_b1` ).
|
|
|
|
**********************************************************************
|
|
|
|
out->write( zcl_demo_abap_aux=>heading( `3a) String Templates (1): Constructing Strings` ) ).
|
|
|
|
"The expression must be convertible to a string. A blank (not
|
|
"within the curly brackets) means a blank in the resulting string.
|
|
DATA(str_c1) = `Hallo`.
|
|
DATA(str_c2) = `how`.
|
|
DATA(str_c3) = `are`.
|
|
DATA(str_c4) = |{ str_c1 } { sy-uname }, | &&
|
|
|{ str_c2 } { str_c3 } you?|.
|
|
|
|
out->write( data = str_c4 name = `str_c4` ).
|
|
|
|
**********************************************************************
|
|
|
|
out->write( zcl_demo_abap_aux=>heading( `3b) String Templates (2): Control Characters` ) ).
|
|
|
|
"Interpretation of character combinations as control characters
|
|
"\n interpreted as a line break
|
|
DATA(str_c5) = |{ str_c1 }\n{ sy-uname },| &&
|
|
|\n{ str_c2 }\n{ str_c3 }\nyou?|.
|
|
|
|
out->write( data = str_c5 name = `str_c5` ).
|
|
out->write( |\n| ).
|
|
|
|
"Excursion: Class CL_ABAP_CHAR_UTILITIES provides attributes and methods as utilities for string processing.
|
|
"See the class documentation.
|
|
"The following examples demonstrate that attributes that contain control characters can be replaced by
|
|
"a representation of control characters in a string template.
|
|
DATA(str_c6) = |{ str_c1 }{ cl_abap_char_utilities=>newline }{ sy-uname }|.
|
|
DATA(str_c7) = |{ str_c1 }\n{ sy-uname }|.
|
|
DATA(str_c8) = |{ str_c1 }{ cl_abap_char_utilities=>horizontal_tab }{ sy-uname }|.
|
|
DATA(str_c9) = |{ str_c1 }\t{ sy-uname }|.
|
|
DATA(str_c10) = |{ str_c1 }{ cl_abap_char_utilities=>cr_lf }{ sy-uname }|.
|
|
DATA(str_c11) = |{ str_c1 }\r\n{ sy-uname }|.
|
|
ASSERT str_c10 = str_c11.
|
|
|
|
out->write( data = str_c6 name = `str_c6` ).
|
|
out->write( |\n| ).
|
|
out->write( data = str_c7 name = `str_c7` ).
|
|
out->write( |\n| ).
|
|
out->write( data = str_c8 name = `str_c8` ).
|
|
out->write( |\n| ).
|
|
out->write( data = str_c9 name = `str_c9` ).
|
|
|
|
**********************************************************************
|
|
|
|
out->write( zcl_demo_abap_aux=>heading( `4) String Templates (3): Formatting Options` ) ).
|
|
"Time, date
|
|
DATA(str_d1a) = |Date: { cl_abap_context_info=>get_system_date( ) DATE = USER }|.
|
|
DATA(str_d1b) = |Time: { cl_abap_context_info=>get_system_time( ) TIME = ISO }|.
|
|
DATA(str_d1c) = |Timestamp: { utclong_current( ) TIMESTAMP = SPACE }|.
|
|
|
|
"Upper, lower case
|
|
DATA(str_d2) = |AbCdEfG|.
|
|
DATA(str_d3) = |{ str_d2 CASE = LOWER }|.
|
|
DATA(str_d4) = |{ str_d2 CASE = UPPER }|.
|
|
|
|
"Width and alignment
|
|
DATA(str_d5) = |{ 'Left' WIDTH = 20 ALIGN = LEFT }<---|.
|
|
DATA(str_d6) = |{ 'Center' WIDTH = 20 ALIGN = CENTER }<---|.
|
|
DATA(str_d7) = |{ 'Right' WIDTH = 20 ALIGN = RIGHT }<---|.
|
|
DATA(str_d8) = |{ 'Left' WIDTH = 20 ALIGN = LEFT PAD = '.' }<---|.
|
|
DATA(str_d9) = |{ 'Center' WIDTH = 20 ALIGN = CENTER PAD = '.' }<---|.
|
|
DATA(str_d10) = |{ 'Right' WIDTH = 20 ALIGN = RIGHT PAD = '.' }<---|.
|
|
|
|
"Numbers
|
|
DATA(str_d11) = |{ - 2 / 3 DECIMALS = 3 }, {
|
|
CONV decfloat34( - 2 / 3 ) DECIMALS = 3 }, {
|
|
CONV f( - 2 / 3 ) DECIMALS = 3 }|.
|
|
|
|
"Escaping \|{} in string templates
|
|
DATA(str_d14) = |\\ \| \{ \}|.
|
|
|
|
out->write( data = str_d1a name = `str_d1a` ).
|
|
out->write( |\n| ).
|
|
out->write( data = str_d1b name = `str_d1b` ).
|
|
out->write( |\n| ).
|
|
out->write( data = str_d1c name = `str_d1c` ).
|
|
out->write( |\n| ).
|
|
out->write( data = str_d3 name = `str_d3` ).
|
|
out->write( |\n| ).
|
|
out->write( data = str_d4 name = `str_d4` ).
|
|
out->write( |\n| ).
|
|
out->write( data = str_d5 name = `str_d5` ).
|
|
out->write( |\n| ).
|
|
out->write( data = str_d6 name = `str_d6` ).
|
|
out->write( |\n| ).
|
|
out->write( data = str_d7 name = `str_d7` ).
|
|
out->write( |\n| ).
|
|
out->write( data = str_d8 name = `str_d8` ).
|
|
out->write( |\n| ).
|
|
out->write( data = str_d9 name = `str_d9` ).
|
|
out->write( |\n| ).
|
|
out->write( data = str_d10 name = `str_d10` ).
|
|
out->write( |\n| ).
|
|
out->write( data = str_d11 name = `str_d11` ).
|
|
out->write( |\n| ).
|
|
out->write( data = str_d14 name = `str_d14` ).
|
|
|
|
**********************************************************************
|
|
|
|
out->write( zcl_demo_abap_aux=>heading( `5) Determining the Length of Strings` ) ).
|
|
|
|
DATA(str_e1) = `abc def ghi `.
|
|
DATA(char_e1) = 'abc def ghi '.
|
|
|
|
"strlen
|
|
"Result depends on the type of the data object
|
|
"Fixed-length string ignores trailing blanks
|
|
DATA(length_e1) = strlen( str_e1 ).
|
|
DATA(length_e2) = strlen( char_e1 ).
|
|
|
|
"numofchar
|
|
"To exclude trailing blanks in any case.
|
|
DATA(length_e3) = numofchar( str_e1 ).
|
|
DATA(length_e4) = numofchar( char_e1 ).
|
|
|
|
"Excursion:
|
|
"To emphasizes modern, expression-enabled ABAP, the expression
|
|
"with the string function can be placed directly in the DO
|
|
"statement instead of having an extra variable.
|
|
DATA(str_e3) = `abcde`.
|
|
DATA(length_e5) = strlen( str_e3 ).
|
|
DATA(int_e1) = 0.
|
|
|
|
DO length_e5 TIMES.
|
|
int_e1 += 1.
|
|
ENDDO.
|
|
|
|
DATA(int_e2) = 0.
|
|
|
|
DO strlen( str_e3 ) TIMES.
|
|
int_e2 += 1.
|
|
ENDDO.
|
|
|
|
out->write( data = length_e1 name = `length_e1` ).
|
|
out->write( |\n| ).
|
|
out->write( data = length_e2 name = `length_e2` ).
|
|
out->write( |\n| ).
|
|
out->write( data = length_e3 name = `length_e3` ).
|
|
out->write( |\n| ).
|
|
out->write( data = length_e4 name = `length_e4` ).
|
|
out->write( |\n| ).
|
|
out->write( data = int_e1 name = `int_e1` ).
|
|
out->write( |\n| ).
|
|
out->write( data = int_e2 name = `int_e2` ).
|
|
|
|
**********************************************************************
|
|
|
|
out->write( zcl_demo_abap_aux=>heading( `6) Concatenating Strings` ) ).
|
|
|
|
DATA(str_f1) = `Hallo`.
|
|
DATA(str_f2) = `world`.
|
|
|
|
"Concatenation using && operator and string templates
|
|
DATA(str_f3) = str_f1 && str_f2.
|
|
DATA(str_f4) = str_f1 && ` ` && str_f2.
|
|
DATA(str_f5) = |{ str_f1 } { str_f2 }|.
|
|
|
|
"CONCATENATE statements
|
|
CONCATENATE str_f1 str_f2 INTO DATA(str_f6).
|
|
"Adding a separation sign using the addition SEPARATED BY
|
|
CONCATENATE str_f1 str_f2 INTO DATA(str_f7) SEPARATED BY ` `.
|
|
CONCATENATE str_f1 str_f2 INTO DATA(str_f8) SEPARATED BY `#`.
|
|
|
|
DATA(char_f1) = '2 trailing blanks: '.
|
|
DATA(char_f2) = '3 trailing blanks: '.
|
|
DATA(char_f3) = '<-'.
|
|
"Keeping trailing blanks in the result when concatenating
|
|
"fixed-length strings. The ones of variable-length strings are
|
|
"respected by default
|
|
CONCATENATE char_f1 char_f2 char_f3
|
|
INTO DATA(char_f4) RESPECTING BLANKS.
|
|
"Trailing blanks are ignored
|
|
CONCATENATE char_f1 char_f2 char_f3 INTO DATA(char_f5).
|
|
|
|
"Example use case: Concatenating smaller text fragments
|
|
"sequentially into a longer character sequence.
|
|
DATA: itab_g TYPE TABLE OF string,
|
|
alphabet1 TYPE string.
|
|
|
|
itab_g = VALUE #( ( `abc` ) ( `def` ) ( `ghi` ) ).
|
|
|
|
LOOP AT itab_g ASSIGNING FIELD-SYMBOL(<abc>).
|
|
alphabet1 = alphabet1 && <abc>.
|
|
"Alternative:
|
|
"CONCATENATE alphabet <abc> INTO alphabet.
|
|
ENDLOOP.
|
|
|
|
"Avoiding loops if your use case is to concatenate lines of an
|
|
"internal table into a string in one go
|
|
CONCATENATE LINES OF itab_g INTO DATA(alphabet2).
|
|
|
|
""Adding a separation sign using the addition SEPARATED BY
|
|
CONCATENATE LINES OF itab_g INTO DATA(alphabet3)
|
|
SEPARATED BY ` `.
|
|
|
|
"String function concat_lines_of
|
|
DATA(alphabet4) = concat_lines_of( table = itab_g ).
|
|
"sep parameter specifying the separation sign
|
|
DATA(alphabet5) = concat_lines_of( table = itab_g sep = `,` ).
|
|
|
|
out->write( data = str_f3 name = `str_f3` ).
|
|
out->write( |\n| ).
|
|
out->write( data = str_f4 name = `str_f4` ).
|
|
out->write( |\n| ).
|
|
out->write( data = str_f5 name = `str_f5` ).
|
|
out->write( |\n| ).
|
|
out->write( data = str_f6 name = `str_f6` ).
|
|
out->write( |\n| ).
|
|
out->write( data = str_f7 name = `str_f7` ).
|
|
out->write( |\n| ).
|
|
out->write( data = str_f8 name = `str_f8` ).
|
|
out->write( |\n| ).
|
|
out->write( data = char_f4 name = `char_f4` ).
|
|
out->write( |\n| ).
|
|
out->write( data = char_f5 name = `char_f5` ).
|
|
out->write( |\n| ).
|
|
out->write( data = alphabet1 name = `alphabet1` ).
|
|
out->write( |\n| ).
|
|
out->write( data = alphabet2 name = `alphabet2` ).
|
|
out->write( |\n| ).
|
|
out->write( data = alphabet3 name = `alphabet3` ).
|
|
out->write( |\n| ).
|
|
out->write( data = alphabet4 name = `alphabet4` ).
|
|
out->write( |\n| ).
|
|
out->write( data = alphabet5 name = `alphabet5` ).
|
|
|
|
**********************************************************************
|
|
|
|
out->write( zcl_demo_abap_aux=>heading( `7) Splitting Strings` ) ).
|
|
|
|
DATA(str_g1) = `Hallo,world,12345`.
|
|
|
|
SPLIT str_g1 AT `,` INTO DATA(str_g2) DATA(str_g3) DATA(str_g4).
|
|
|
|
"Less data objects than possible splittings
|
|
SPLIT str_g1 AT `,` INTO DATA(str_g5) DATA(str_g6).
|
|
|
|
"Splitting string into an internal table
|
|
DATA itab_g1 TYPE TABLE OF string.
|
|
|
|
SPLIT str_g1 AT ',' INTO TABLE itab_g1.
|
|
|
|
"Getting the value of a specific segment
|
|
DATA(str_g7) = segment( val = str_g1 index = 2 sep = `,` ).
|
|
|
|
"Example with segment
|
|
"A string is split and the values of segments are retrieved. Here,
|
|
"all segments are retrieved and inserted into an internal table
|
|
"using a DO loop. If you specify an empty string, an exception of
|
|
"the class CX_SY_STRG_PAR_VAL is raised. This is true for this
|
|
"example since the DO loop inevitably runs into the error because
|
|
"of not specifying an appropriate number of loops. Note that
|
|
"if the index parameter of the segment function is positive, the
|
|
"occurrences are counted from the left. If index is negative, the
|
|
"occurrences are counted from the right.
|
|
DATA itab_g2 TYPE TABLE OF string.
|
|
DO.
|
|
TRY.
|
|
DATA(str_g8) = segment( val = str_g1
|
|
index = sy-index
|
|
sep = `,` ).
|
|
|
|
APPEND |Segment value: '{ str_g8 }' | &&
|
|
|Segment index: '{ sy-index }'| TO itab_g2.
|
|
|
|
CATCH cx_sy_strg_par_val.
|
|
DATA(seg_nom) = |There are { sy-index - 1 } | &&
|
|
|segments in the string.|.
|
|
EXIT.
|
|
ENDTRY.
|
|
ENDDO.
|
|
|
|
out->write( data = str_g2 name = `str_g2` ).
|
|
out->write( |\n| ).
|
|
out->write( data = str_g3 name = `str_g3` ).
|
|
out->write( |\n| ).
|
|
out->write( data = str_g4 name = `str_g4` ).
|
|
out->write( |\n| ).
|
|
out->write( data = str_g5 name = `str_g5` ).
|
|
out->write( |\n| ).
|
|
out->write( data = str_g6 name = `str_g6` ).
|
|
out->write( |\n| ).
|
|
out->write( data = itab_g1 name = `itab_g1` ).
|
|
out->write( |\n| ).
|
|
out->write( data = str_g7 name = `str_g7` ).
|
|
out->write( |\n| ).
|
|
out->write( data = str_g8 name = `str_g8` ).
|
|
out->write( |\n| ).
|
|
out->write( data = itab_g2 name = `itab_g2` ).
|
|
out->write( |\n| ).
|
|
out->write( data = seg_nom name = `seg_nom` ).
|
|
|
|
**********************************************************************
|
|
|
|
out->write( zcl_demo_abap_aux=>heading( `Modifying Strings` ) ).
|
|
out->write( |8) Transforming to Lower and Upper Case\n\n| ).
|
|
|
|
DATA(str_h1) = `It's a string`.
|
|
DATA(str_h2) = str_h1.
|
|
|
|
"The string functions store the result in a target variable.
|
|
DATA(str_h3) = to_upper( str_h1 ).
|
|
DATA(str_h4) = to_lower( str_h1 ).
|
|
|
|
"TRANSLATE does the transformation on the source variable.
|
|
TRANSLATE str_h1 TO UPPER CASE.
|
|
TRANSLATE str_h2 TO LOWER CASE.
|
|
|
|
"to_mixed/from_mixed functions
|
|
"sep: Specifies the separator
|
|
"case: A character-like text field. A small character specifies
|
|
"that the first character of the string is in lower case. If the
|
|
"specification is, for example, case = 'X', the first character
|
|
"is capitalized.
|
|
"min: A positive number that specifies the minimum number of
|
|
"characters that must appear before the separator. The default
|
|
"value is 1.
|
|
DATA(str_h5) = `A_GREAT_STRING`.
|
|
DATA(str_h6) = to_mixed( val = str_h5 sep = `_` ).
|
|
DATA(str_h7) = to_mixed( val = str_h5 sep = `_` case = 'x' ).
|
|
DATA(str_h8) = to_mixed( val = str_h5 sep = `_`
|
|
case = 'a' min = 3 ).
|
|
|
|
DATA(str_h9) = from_mixed( val = `someGreatString` sep = ` `
|
|
case = 'a' min = 4 ).
|
|
|
|
out->write( data = str_h3 name = `str_h3` ).
|
|
out->write( |\n| ).
|
|
out->write( data = str_h4 name = `str_h4` ).
|
|
out->write( |\n| ).
|
|
out->write( data = str_h1 name = `str_h1` ).
|
|
out->write( |\n| ).
|
|
out->write( data = str_h2 name = `str_h2` ).
|
|
out->write( |\n| ).
|
|
out->write( data = str_h6 name = `str_h6` ).
|
|
out->write( |\n| ).
|
|
out->write( data = str_h7 name = `str_h7` ).
|
|
out->write( |\n| ).
|
|
out->write( data = str_h8 name = `str_h8` ).
|
|
out->write( |\n| ).
|
|
out->write( data = str_h9 name = `str_h9` ).
|
|
|
|
**********************************************************************
|
|
|
|
out->write( zcl_demo_abap_aux=>heading( `9) Shifting Content in Strings` ) ).
|
|
|
|
DATA(str_i1) = `hallo`.
|
|
DATA(str_i2) = str_i1.
|
|
DATA(str_i3) = str_i1.
|
|
DATA(str_i4) = str_i1.
|
|
|
|
"No addition; string is shifted one place to the left
|
|
SHIFT str_i2.
|
|
|
|
"Shifting string by n places; without direction,
|
|
"left by default
|
|
SHIFT str_i3 BY 2 PLACES.
|
|
|
|
"Direction explicitly specified
|
|
"Variable-length strings are extended
|
|
SHIFT str_i4 BY 3 PLACES RIGHT.
|
|
|
|
DATA(char_i1) = 'world '.
|
|
DATA(char_i2) = char_i1.
|
|
DATA(char_i3) = char_i1.
|
|
DATA(str_i5) = `world `.
|
|
|
|
"Comparison of behavior for fixed- and variable-length strings
|
|
SHIFT char_i1 BY 3 PLACES RIGHT.
|
|
SHIFT str_i5 BY 3 PLACES RIGHT.
|
|
|
|
"CIRCULAR addition: characters that are moved out of the string are
|
|
"added at the other end again
|
|
SHIFT char_i2 BY 3 PLACES RIGHT CIRCULAR.
|
|
SHIFT char_i3 BY 2 PLACES LEFT CIRCULAR.
|
|
|
|
DATA(str_i6) = ` hallo world `.
|
|
DATA(str_i7) = str_i6.
|
|
|
|
"Moving characters up to a specific character set
|
|
SHIFT str_i6 UP TO 'or'.
|
|
|
|
"Deleting leading and trailing characters with this sequence
|
|
"of statements
|
|
SHIFT str_i7 RIGHT DELETING TRAILING ` `.
|
|
SHIFT str_i7 LEFT DELETING LEADING ` `.
|
|
|
|
"String functions storing the result in a target variable
|
|
DATA(str_i8) = `some string`.
|
|
|
|
"shift_left
|
|
DATA(str_i9) = shift_left( val = str_i8 places = 3 ).
|
|
|
|
DATA(str_i10) = shift_left( val = str_i8 circular = 7 ).
|
|
|
|
"shift_right
|
|
"Note: When the parameter places is specified, the function
|
|
"shift_right has a different behavior than the SHIFT statement.
|
|
"Here, the length of the string is reduced. SHIFT extends the
|
|
"length or it remains the same.
|
|
DATA(str_i11) = shift_right( val = str_i8 places = 3 ).
|
|
|
|
DATA(str_i12) = `shift_right and trailing blanks `.
|
|
|
|
"sub: Specifying a substring; all substrings in the string that
|
|
"match the value are removed (sub also available for shift_left)
|
|
DATA(str_i13) = shift_right( val = str_i12
|
|
sub = ` and trailing blanks ` ).
|
|
|
|
DATA(str_i14) = shift_right( val = str_i12 sub = ` ` ).
|
|
|
|
DATA(str_i15) = shift_right( val = str_i12 ). "Same effect as above
|
|
|
|
out->write( |SHIFT statements:\n\n| ).
|
|
out->write( data = str_i2 name = `str_i2` ).
|
|
out->write( |\n| ).
|
|
out->write( data = str_i3 name = `str_i3` ).
|
|
out->write( |\n| ).
|
|
out->write( data = str_i4 name = `str_i4` ).
|
|
out->write( |\n| ).
|
|
out->write( data = char_i1 name = `char_i1` ).
|
|
out->write( |\n| ).
|
|
out->write( data = str_i5 name = `str_i5` ).
|
|
out->write( |\n| ).
|
|
out->write( data = char_i2 name = `char_i2` ).
|
|
out->write( |\n| ).
|
|
out->write( data = char_i3 name = `char_i3` ).
|
|
out->write( |\n| ).
|
|
out->write( data = str_i6 name = `str_i6` ).
|
|
out->write( |\n| ).
|
|
out->write( data = str_i7 name = `str_i7` ).
|
|
out->write( |\n| ).
|
|
|
|
out->write( |String functions:\n\n| ).
|
|
out->write( |\n| ).
|
|
out->write( data = str_i9 name = `str_i9` ).
|
|
out->write( |\n| ).
|
|
out->write( data = str_i10 name = `str_i10` ).
|
|
out->write( |\n| ).
|
|
out->write( data = str_i11 name = `str_i11` ).
|
|
out->write( |\n| ).
|
|
out->write( data = str_i13 name = `str_i13` ).
|
|
out->write( |\n| ).
|
|
out->write( data = str_i14 name = `str_i14` ).
|
|
out->write( |\n| ).
|
|
out->write( data = str_i15 name = `str_i15` ).
|
|
|
|
**********************************************************************
|
|
|
|
out->write( zcl_demo_abap_aux=>heading( `10) Condensing Strings` ) ).
|
|
|
|
DATA(char_j1) = ' some text '.
|
|
DATA(char_j2) = ' some more text '.
|
|
DATA(char_j3) = ' a third text field literal '.
|
|
|
|
"No addition: Removes leading and trailing blanks. This is also
|
|
"true for multiple blanks. It also replaces sequences of multiple
|
|
"blanks with a single blank.
|
|
CONDENSE char_j1.
|
|
CONDENSE char_j2.
|
|
|
|
"NO-GAPS: Removes all blanks, also between words. When NO-GAPS
|
|
"is used with variable-length strings, trailing blanks remain
|
|
"removed.
|
|
CONDENSE char_j3 NO-GAPS.
|
|
|
|
"RESPECTING BLANKS: Avoiding condensing
|
|
"A use case might be the assignment of strings with fixed- to
|
|
"variable-length strings.
|
|
DATA(char_j4) = ' abcef '.
|
|
DATA(char_j5) = ' ghij '.
|
|
DATA str_j TYPE string.
|
|
|
|
"Result: ' abcef ghij '
|
|
CONCATENATE char_j4 char_j5 INTO str_j RESPECTING BLANKS.
|
|
|
|
"String function condense
|
|
"The advantage of using the string functions is
|
|
"that you can also specify random characters to be removed and
|
|
"not only blanks.
|
|
DATA(str_j1) = ` hi there `.
|
|
|
|
"No parameters specified (i. e. their default values are provided);
|
|
"works like CONDENSE statements without the NO-GAPS addition
|
|
DATA(str_j2) = condense( str_j1 ).
|
|
|
|
"Parameter 'from' specified with an initial string, 'del'/'to' not
|
|
"specified: Removes leading and trailing blanks. The 'from'
|
|
"parameter could also be specified with a text field literal:
|
|
"from = ' '
|
|
DATA(str_j3) = condense( val = str_j1 from = `` ).
|
|
|
|
"Parameter 'to' specified with an initial string, 'from'/'del' not
|
|
"specified: works like CONDENSE statements with the NO-GAPS
|
|
"addition
|
|
DATA(str_j4) = condense( val = str_j1 to = `` ).
|
|
|
|
DATA(str_j5) = `ZZseeZZZyouZZ`.
|
|
DATA(str_j6) = condense( val = str_j5 del = `Z` ).
|
|
|
|
"Parameters 'from', 'to' and 'del' are specified: Leading and
|
|
"trailing characters specified in 'del' are first removed. Then,
|
|
"in the remaining string, all substrings composed of characters
|
|
"specified in 'from' are replaced with the first character of the
|
|
"string specified in the 'to' parameter (in the example, it is a
|
|
"blank; the characters 'a', 'b', 'c' are not respected at all).
|
|
DATA(str_j7) = condense( val = str_j5
|
|
del = `Z`
|
|
from = `Z`
|
|
to = ` abc` ).
|
|
|
|
out->write( |CONDENSE statements:\n| ).
|
|
out->write( |\n| ).
|
|
out->write( data = char_j1 name = `char_j1` ).
|
|
out->write( |\n| ).
|
|
out->write( data = char_j2 name = `char_j2` ).
|
|
out->write( |\n| ).
|
|
out->write( data = char_j3 name = `char_j3` ).
|
|
out->write( |\n| ).
|
|
out->write( data = str_j name = `str_j` ).
|
|
out->write( |\n| ).
|
|
out->write( zcl_demo_abap_aux=>heading( `String function condense:` ) ).
|
|
out->write( data = str_j2 name = `str_j2` ).
|
|
out->write( |\n| ).
|
|
out->write( data = str_j3 name = `str_j3` ).
|
|
out->write( |\n| ).
|
|
out->write( data = str_j4 name = `str_j4` ).
|
|
out->write( |\n| ).
|
|
out->write( data = str_j6 name = `str_j6` ).
|
|
out->write( |\n| ).
|
|
out->write( data = str_j7 name = `str_j7` ).
|
|
|
|
**********************************************************************
|
|
|
|
out->write( zcl_demo_abap_aux=>heading( `11) Reversing Strings` ) ).
|
|
|
|
DATA(str_k) = reverse( `ollah` ).
|
|
|
|
out->write( data = str_k name = `str_k` ).
|
|
|
|
**********************************************************************
|
|
|
|
out->write( zcl_demo_abap_aux=>heading( `12) Inserting Substrings into Strings` ) ).
|
|
|
|
DATA(str_l1) = `abcghi`.
|
|
|
|
"Inserting into specific position
|
|
DATA(str_l2) = insert( val = str_l1 sub = `def` off = 3 ).
|
|
|
|
"off is optional. If not specified (default value off = 0)
|
|
"the result is like concatenating a string with &&
|
|
DATA(str_l3) = insert( val = str_l1 sub = `def` ).
|
|
|
|
DATA(str_l4) = `def` && str_l1.
|
|
|
|
out->write( data = str_l2 name = `str_l2` ).
|
|
out->write( |\n| ).
|
|
out->write( data = str_l3 name = `str_l3` ).
|
|
out->write( |\n| ).
|
|
out->write( data = str_l4 name = `str_l4` ).
|
|
|
|
**********************************************************************
|
|
|
|
out->write( zcl_demo_abap_aux=>heading( `13) Overlaying Content` ) ).
|
|
|
|
DATA(incl) = '==============================CP'.
|
|
DATA(cl_name) = 'CL_SOME_CLASS '.
|
|
|
|
"Addition ONLY is not specified: All blanks are replaced
|
|
OVERLAY cl_name WITH incl.
|
|
|
|
DATA(t1) = 'a.b.c.a.b.c.A'.
|
|
DATA(t2) = 'z.x.y.Z.x.y.z'.
|
|
|
|
"Addition ONLY is specified: All characters that are specified after ONLY and that
|
|
"occur in the operand are replaced. Note that this is case-sensitive.
|
|
OVERLAY t1 WITH t2 ONLY 'ab'.
|
|
|
|
out->write( data = cl_name name = `cl_name` ).
|
|
out->write( |\n| ).
|
|
out->write( data = t1 name = `t1` ).
|
|
|
|
**********************************************************************
|
|
|
|
out->write( zcl_demo_abap_aux=>heading( `14) Processing Substrings` ) ).
|
|
|
|
DATA(str_m1) = `Lorem ipsum dolor sit amet`.
|
|
|
|
"Extracting substring starting at a specific position
|
|
"'len' not specified means the rest of the remaining characters are
|
|
"respected
|
|
DATA(str_m2) = substring( val = str_m1 off = 6 ).
|
|
|
|
"Extracting substring with a specific length
|
|
"'off' is not specified and has the default value 0.
|
|
DATA(str_m3) = substring( val = str_m1 len = 5 ).
|
|
|
|
"Specifying both off and len parameters
|
|
DATA(str_m4) = substring( val = str_m1 off = 6 len = 5 ).
|
|
|
|
"Excursion: Getting last character of a string
|
|
DATA(str_m5) = substring( val = str_m1
|
|
off = strlen( str_m1 ) - 1
|
|
len = 1 ). "t
|
|
|
|
"Offset and length specification using the + sign after a variable
|
|
"After +, it is the offset, length is specified within parentheses.
|
|
DATA(str_m6) = str_m1+0(5).
|
|
|
|
"* means respecting the rest of the remaining string
|
|
DATA(str_m7) = str_m1+12(*).
|
|
|
|
"Excursion: Write access on substrings in fixed-length strings
|
|
DATA(char_m1) = 'Lorem ipsum dolor sit amet'.
|
|
DATA(char_m2) = char_m1.
|
|
DATA(char_m3) = char_m1.
|
|
|
|
"Deleting content
|
|
CLEAR char_m2+11(*).
|
|
"Modifying string
|
|
char_m3+0(5) = 'abcde'.
|
|
|
|
"More string functions to access substrings
|
|
"Note that lots of parameters are possible (not all covered here).
|
|
DATA(str_m8) = `aa1bb2aa3bb4`.
|
|
|
|
"Extracting a substring ...
|
|
"... after a specified substring
|
|
DATA(str_m9) = substring_after( val = str_m8 sub = `aa` ).
|
|
|
|
"... after a specified substring specifying the occurence in a
|
|
"string and restricting the length
|
|
DATA(str_m10) = substring_after( val = str_m8 sub = `aa`
|
|
occ = 2 len = 4 ).
|
|
|
|
"... before a specified substring
|
|
DATA(str_m11) = substring_before( val = str_m8 sub = `b2` ).
|
|
|
|
"... from a specified substring on. It includes the substring
|
|
"specified in sub. len/off and other parameters are possible.
|
|
DATA(str_m12) = substring_from( val = str_m8 sub = `a3` ).
|
|
|
|
"... up to a specified substring. It includes the substring
|
|
"specified in sub. len/off and other parameters are possible.
|
|
"aa1bb2aa3b
|
|
DATA(str_m13) = substring_to( val = str_m8 sub = `3b` ).
|
|
|
|
out->write( data = str_m2 name = `str_m2` ).
|
|
out->write( |\n| ).
|
|
out->write( data = str_m3 name = `str_m3` ).
|
|
out->write( |\n| ).
|
|
out->write( data = str_m4 name = `str_m4` ).
|
|
out->write( |\n| ).
|
|
out->write( data = str_m5 name = `str_m5` ).
|
|
out->write( |\n| ).
|
|
out->write( data = str_m6 name = `str_m6` ).
|
|
out->write( |\n| ).
|
|
out->write( data = str_m7 name = `str_m7` ).
|
|
out->write( |\n| ).
|
|
out->write( data = char_m2 name = `char_m2` ).
|
|
out->write( |\n| ).
|
|
out->write( data = char_m3 name = `char_m3` ).
|
|
out->write( |\n| ).
|
|
out->write( data = str_m9 name = `str_m9` ).
|
|
out->write( |\n| ).
|
|
out->write( data = str_m10 name = `str_m10` ).
|
|
out->write( |\n| ).
|
|
out->write( data = str_m11 name = `str_m11` ).
|
|
out->write( |\n| ).
|
|
out->write( data = str_m12 name = `str_m12` ).
|
|
out->write( |\n| ).
|
|
out->write( data = str_m13 name = `str_m13` ).
|
|
|
|
**********************************************************************
|
|
|
|
out->write( zcl_demo_abap_aux=>heading( `Searching and Replacing in Strings` ) ).
|
|
out->write( |15) Searching Specific Characters in Strings Using Comparison Operators and String Functions\n| ).
|
|
|
|
DATA(str_n1) = `cheers`.
|
|
|
|
"CA (contains any)
|
|
"sy-fdpos contains the offset of the first found character.
|
|
"If nothing is found, sy-fdpos contains the length of the string.
|
|
"Note that position 0 stands for the very first position.
|
|
IF str_n1 CA `aeiou`.
|
|
out->write( |CA: str_n1 contains any of the characters. | &&
|
|
|The position of the first found character is { sy-fdpos }.| ).
|
|
out->write( |\n| ).
|
|
ELSE.
|
|
out->write( |CA: str_n1 does not contain any of the characters. | &&
|
|
|The length of str_n1 is { sy-fdpos }.| ).
|
|
out->write( |\n| ).
|
|
ENDIF.
|
|
|
|
"NA (contains not any)
|
|
IF str_n1 NA `xyz`.
|
|
out->write( |NA: str_n1 does not contain any of the characters.| &&
|
|
|The length of str_n1 is { sy-fdpos }.| ).
|
|
out->write( |\n| ).
|
|
ELSE.
|
|
out->write( |NA: str_n1 contains any of the characters. | &&
|
|
|The position of the first found character is { sy-fdpos }.| ).
|
|
out->write( |\n| ).
|
|
ENDIF.
|
|
|
|
"Determining if a string is exclusively composed of a certain
|
|
"character set
|
|
IF str_n1 CO `rs`.
|
|
out->write( |CO: str_n1 contains only the characters. |
|
|
&& |The length of str_n1 is { sy-fdpos }.| ).
|
|
out->write( |\n| ).
|
|
ELSE.
|
|
out->write( |CO: str_n1 does not contain only the characters. |
|
|
&& |Offset of the first character in str_n1 that is not |
|
|
&& |contained in the second operand: { sy-fdpos }.| ).
|
|
out->write( |\n| ).
|
|
ENDIF.
|
|
|
|
"Negation of CO
|
|
IF str_n1 CN `chers`.
|
|
out->write( |CN: str_n1 does not contain only the characters. |
|
|
&& |Offset of the first character in str_n1 that is |
|
|
&& |not contained in the second operand: { sy-fdpos }.| ).
|
|
out->write( |\n| ).
|
|
ELSE.
|
|
out->write( |CN: str_n1 contains only the characters. |
|
|
&& |The length of str_n1 is { sy-fdpos }.| ).
|
|
out->write( |\n| ).
|
|
ENDIF.
|
|
|
|
"String functions
|
|
DATA(str_n2) = `Pieces of cakes.`.
|
|
|
|
"find_end returns the sum of the offset of the occurrence
|
|
DATA(res_n3) = find_end( val = str_n2 sub = `of` ). "9
|
|
|
|
"find_any_of returns the offset of the occurrence of any character contained in substring
|
|
"The search is always case-sensitive.
|
|
DATA(res_n4) = find_any_of( val = str_n2 sub = `x523z4e` ).
|
|
DATA(res_n5) = find_any_of( val = str_n2 sub = `zwq85t` ).
|
|
|
|
"find_any_not_of: Negation of the one above
|
|
"The search is always case-sensitive.
|
|
DATA(res_n6) = find_any_not_of( val = str_n2 sub = `ieces` ).
|
|
DATA(res_n7) = find_any_not_of( val = str_n2 sub = `P` ).
|
|
|
|
"count returns the number of all occurrences
|
|
DATA(res_n8) = count( val = str_n2 sub = `e` ).
|
|
DATA(res_n9) = count( val = str_n2 sub = `x` ).
|
|
|
|
"count_any_of
|
|
DATA(res_n10) = count_any_of( val = str_n2 sub = `x523z4e` ).
|
|
DATA(res_n11) = count_any_of( val = str_n2 sub = `eco` ).
|
|
|
|
"count_any_not_of
|
|
DATA(res_n12) = count_any_not_of( val = str_n2 sub = `fP` ).
|
|
DATA(res_n13) = count_any_not_of( val = str_n2 sub = `Piecs ofak.` ).
|
|
|
|
out->write( data = res_n3 name = `res_n3` ).
|
|
out->write( |\n| ).
|
|
out->write( data = res_n4 name = `res_n4` ).
|
|
out->write( |\n| ).
|
|
out->write( data = res_n5 name = `res_n5` ).
|
|
out->write( |\n| ).
|
|
out->write( data = res_n6 name = `res_n6` ).
|
|
out->write( |\n| ).
|
|
out->write( data = res_n7 name = `res_n7` ).
|
|
out->write( |\n| ).
|
|
out->write( data = res_n8 name = `res_n8` ).
|
|
out->write( |\n| ).
|
|
out->write( data = res_n9 name = `res_n9` ).
|
|
out->write( |\n| ).
|
|
out->write( data = res_n10 name = `res_n10` ).
|
|
out->write( |\n| ).
|
|
out->write( data = res_n11 name = `res_n11` ).
|
|
out->write( |\n| ).
|
|
out->write( data = res_n12 name = `res_n12` ).
|
|
out->write( |\n| ).
|
|
out->write( data = res_n13 name = `res_n13` ).
|
|
|
|
**********************************************************************
|
|
|
|
out->write( zcl_demo_abap_aux=>heading( `16) Replacing Specific Characters in Strings` ) ).
|
|
|
|
DATA(str_o1) = `___abc_def_____ghi_`.
|
|
|
|
"The replacement is done as follows: Each character specified in
|
|
"'from' is replaced by the character in 'to' that is on the same
|
|
"position, i. e. the second character in 'from' is replaced by the
|
|
"second character specified in 'to'. If there is no equivalent in
|
|
"'to', the character in 'from' is removed from the result.
|
|
|
|
"abcdefgZZ
|
|
DATA(str_o2) = translate( val = str_o1 from = `hi_` to = `ZZ` ).
|
|
|
|
"ZZZabcZdefZZZZZghiZ
|
|
DATA(str_o3) = translate( val = str_o1 from = `_` to = `ZZ` ).
|
|
|
|
"TRANSLATE statement. The value after USING is interpreted as a
|
|
"string composed of character pairs. Starting with the first pair,
|
|
"a search is performed in text for the first character in every
|
|
"pair and each occurrence is replaced with the second character of
|
|
"the pair.
|
|
"...Zbc.def.....Yhi.
|
|
TRANSLATE str_o1 USING `_.aZgY`.
|
|
|
|
out->write( data = str_o2 name = `str_o2` ).
|
|
out->write( |\n| ).
|
|
out->write( data = str_o3 name = `str_o3` ).
|
|
out->write( |\n| ).
|
|
out->write( data = str_o1 name = `str_o1` ).
|
|
|
|
**********************************************************************
|
|
|
|
out->write( zcl_demo_abap_aux=>heading( `Searching for Substrings in Strings` ) ).
|
|
out->write( |17) Substring Search: Simple Search Using Comparison Operators\n| ).
|
|
|
|
DATA(str_p1) = `cheers`.
|
|
|
|
"CS (contains string)
|
|
"sy-fdpos contains the offset of the found substring.
|
|
"If the substring is not found, sy-fdpos contains the length of the
|
|
"searched string.
|
|
IF str_p1 CS `rs`.
|
|
out->write( |CS: The string contains the substring. |
|
|
&& |The offset is { sy-fdpos }.| ).
|
|
out->write( |\n| ).
|
|
ELSE.
|
|
out->write( |CS: The string does not contain the substring. |
|
|
&& |The length of the string is { sy-fdpos }.| ).
|
|
out->write( |\n| ).
|
|
ENDIF.
|
|
|
|
"NS (contains no string)
|
|
IF str_p1 NS `abc`.
|
|
out->write( |NS: The string does not contain the substring. |
|
|
&& |The length of the string is { sy-fdpos }.| ).
|
|
out->write( |\n| ).
|
|
ELSE.
|
|
out->write( |NS: The string contains the substring. |
|
|
&& |The offset is { sy-fdpos }.| ).
|
|
out->write( |\n| ).
|
|
ENDIF.
|
|
|
|
**********************************************************************
|
|
|
|
out->write( zcl_demo_abap_aux=>heading( `18) Substring Search in Strings ` &&
|
|
`Using FIND Statements` ) ).
|
|
"The code examples demonstrate different additions.
|
|
|
|
DATA(str_qa) = `She sells seashells by the seashore.`.
|
|
|
|
"Determining if a substring is found
|
|
"Simple find statement
|
|
FIND `se` IN str_qa.
|
|
|
|
IF sy-subrc = 0.
|
|
out->write( `'se' found in the string` ).
|
|
ELSE.
|
|
out->write( `'se' not found in the string` ).
|
|
ENDIF.
|
|
|
|
out->write( |\n| ).
|
|
|
|
"Addition SUBSTRING is optional
|
|
FIND SUBSTRING `hi` IN str_qa.
|
|
|
|
IF sy-subrc = 0.
|
|
out->write( `'hi' Found in the string` ).
|
|
ELSE.
|
|
out->write( `'hi' not found in the string` ).
|
|
ENDIF.
|
|
|
|
out->write( |\n| ).
|
|
out->write( |\n| ).
|
|
|
|
"The following examples use the additions MATCH COUNT and MATCH OFFSET
|
|
"to determine the number of occurrences and offset and for display purposes.
|
|
|
|
"Addition FIRST OCCURRENCE OF: Explicit specification to search
|
|
"for the first occurrence
|
|
FIND FIRST OCCURRENCE OF `se` IN str_qa
|
|
MATCH COUNT DATA(cnt_q1)
|
|
MATCH OFFSET DATA(off_q2).
|
|
|
|
"Omitting FIRST OCCURRENCE OF and ALL OCCURRENCES OF addition means
|
|
"searching for the first occurrence by default; same effect as the
|
|
"previous statement
|
|
FIND `se` IN str_qa
|
|
MATCH COUNT DATA(cnt_q3)
|
|
MATCH OFFSET DATA(off_q4).
|
|
|
|
"Addition ALL OCCURRENCES: Searching for all occurrences
|
|
FIND ALL OCCURRENCES OF `se` IN str_qa
|
|
MATCH COUNT DATA(cnt_q5)
|
|
MATCH OFFSET DATA(off_q6). "value for the last occurrence
|
|
|
|
"Addition IN SECTION ... OF:
|
|
"Searching in a specified section; both additions OFFSET and LENGTH
|
|
"are specified
|
|
FIND ALL OCCURRENCES OF `se`
|
|
IN SECTION OFFSET 9 LENGTH 5 OF str_qa
|
|
MATCH COUNT DATA(cnt_q7)
|
|
MATCH OFFSET DATA(off_q8).
|
|
|
|
"Only LENGTH specified (OFFSET is 0 by default)
|
|
FIND ALL OCCURRENCES OF `se`
|
|
IN SECTION LENGTH 7 OF str_qa
|
|
MATCH COUNT DATA(cnt_q9)
|
|
MATCH OFFSET DATA(off_q10).
|
|
|
|
"Only OFFSET specified (LENGTH: up to end of string)
|
|
FIND ALL OCCURRENCES OF `se`
|
|
IN SECTION OFFSET 7 OF str_qa
|
|
MATCH COUNT DATA(cnt_q11).
|
|
|
|
"Another string to be searched
|
|
DATA(str_qb) = `abap ABAP abap`.
|
|
|
|
"Further additional options for advanced evaluation options
|
|
|
|
"Specifying the case-sensitivity of the search
|
|
"Not specifying the CASE addition means RESPECTING CASE is used by default.
|
|
"Here, it is explicitly specified.
|
|
FIND FIRST OCCURRENCE OF `A` IN str_qb
|
|
MATCH OFFSET DATA(off_q12)
|
|
RESPECTING CASE.
|
|
|
|
"Making search case-insensitive
|
|
FIND FIRST OCCURRENCE OF `A` IN str_qb
|
|
MATCH OFFSET DATA(off_q13)
|
|
IGNORING CASE.
|
|
|
|
"MATCH LENGTH addition
|
|
"The example uses a regular expression: Non-greedy search for
|
|
"a substring starting with lower case a up to an upper case P
|
|
FIND FIRST OCCURRENCE OF PCRE `a.*?P` IN str_qb
|
|
MATCH LENGTH DATA(len_q14) "9
|
|
RESPECTING CASE.
|
|
|
|
"RESULTS addition
|
|
"Example: Because of using ALL OCCURRENCES, the data object declared
|
|
"inline automatically has the type match_result_tab
|
|
FIND ALL OCCURRENCES OF `ab` IN str_qb
|
|
RESULTS DATA(res_q15)
|
|
IGNORING CASE.
|
|
|
|
"Because of searching for the first occurrence, the data object declared
|
|
"inline automatically has the type match_result
|
|
FIND FIRST OCCURRENCE OF `ab` IN str_qb
|
|
RESULTS DATA(res_q16)
|
|
IGNORING CASE.
|
|
|
|
out->write( data = cnt_q1 name = `cnt_q1` ).
|
|
out->write( |\n| ).
|
|
out->write( data = off_q2 name = `off_q2` ).
|
|
out->write( |\n| ).
|
|
out->write( data = cnt_q3 name = `cnt_q3` ).
|
|
out->write( |\n| ).
|
|
out->write( data = off_q4 name = `off_q4` ).
|
|
out->write( |\n| ).
|
|
out->write( data = cnt_q5 name = `cnt_q5` ).
|
|
out->write( |\n| ).
|
|
out->write( data = off_q6 name = `off_q6` ).
|
|
out->write( |\n| ).
|
|
out->write( data = cnt_q7 name = `cnt_q7` ).
|
|
out->write( |\n| ).
|
|
out->write( data = off_q8 name = `off_q8` ).
|
|
out->write( |\n| ).
|
|
out->write( data = cnt_q9 name = `cnt_q9` ).
|
|
out->write( |\n| ).
|
|
out->write( data = off_q10 name = `off_q10` ).
|
|
out->write( |\n| ).
|
|
out->write( data = cnt_q11 name = `cnt_q11` ).
|
|
out->write( |\n| ).
|
|
out->write( data = off_q12 name = `off_q12` ).
|
|
out->write( |\n| ).
|
|
out->write( data = off_q13 name = `off_q13` ).
|
|
out->write( |\n| ).
|
|
out->write( data = len_q14 name = `len_q14` ).
|
|
out->write( |\n| ).
|
|
out->write( data = res_q15 name = `res_q15` ).
|
|
out->write( |\n| ).
|
|
out->write( data = res_q16 name = `res_q16` ).
|
|
|
|
**********************************************************************
|
|
|
|
out->write( zcl_demo_abap_aux=>heading( `19) Substring Search in Internal Tables ` &&
|
|
`Using FIND ... IN TABLE Statements` ) ).
|
|
|
|
DATA(str_table_r) = VALUE string_table( ( `aZbzZ` ) ( `cdZze` ) ( `Zzzf` ) ( `ghz` ) ).
|
|
|
|
"Finding all occurrences in a table
|
|
"Note: res_tab is of type match_result_tab
|
|
"You can also restrict the search range in an internal table; see an example
|
|
"in the context of REPLACE ... IN TABLE
|
|
FIND ALL OCCURRENCES OF `Z`
|
|
IN TABLE str_table_r
|
|
RESULTS DATA(res_r1)
|
|
RESPECTING CASE.
|
|
|
|
"Finding the first occurrence in a table
|
|
"Note: res_struc, which is declared inline here, is of type match_result
|
|
FIND FIRST OCCURRENCE OF `Z`
|
|
IN TABLE str_table_r
|
|
RESULTS DATA(res_r2)
|
|
RESPECTING CASE.
|
|
|
|
"Alternative to the statement above (storing the information in individual data objects)
|
|
FIND FIRST OCCURRENCE OF `Z`
|
|
IN TABLE str_table_r
|
|
MATCH LINE DATA(line_r3)
|
|
MATCH OFFSET DATA(off_r4)
|
|
MATCH LENGTH DATA(len_r5)
|
|
RESPECTING CASE.
|
|
|
|
out->write( data = res_r1 name = `res_r1` ).
|
|
out->write( |\n| ).
|
|
out->write( data = res_r2 name = `res_r2` ).
|
|
out->write( |\n| ).
|
|
out->write( data = line_r3 name = `line_r3` ).
|
|
out->write( |\n| ).
|
|
out->write( data = off_r4 name = `off_r4` ).
|
|
out->write( |\n| ).
|
|
out->write( data = len_r5 name = `len_r5` ).
|
|
|
|
**********************************************************************
|
|
|
|
out->write( zcl_demo_abap_aux=>heading( `20) Substring Search in Strings ` &&
|
|
`Using the String Function find` ) ).
|
|
|
|
DATA(str_s) = `Pieces of cakes.`.
|
|
|
|
"Searching for substring
|
|
"Returns offset of substring found
|
|
DATA(res_s1) = find( val = str_s sub = `ca` ).
|
|
|
|
"Substring not found returns -1
|
|
DATA(res_s2) = find( val = str_s sub = `xy` ).
|
|
|
|
"Actual parameter of sub must not be initial when using the find function
|
|
TRY.
|
|
DATA(res_s3) = find( val = str_s sub = `` ).
|
|
CATCH cx_sy_strg_par_val.
|
|
"Nope!
|
|
ENDTRY.
|
|
|
|
"The search is case-sensitive by default
|
|
DATA(res_s4) = find( val = str_s sub = `OF` ).
|
|
"Making search case-insensitive
|
|
DATA(res_s5) = find( val = str_s sub = `OF` case = abap_false ).
|
|
|
|
"Specifying occ
|
|
DATA(res_s6) = find( val = str_s sub = `c` ).
|
|
DATA(res_s7) = find( val = str_s sub = `c` occ = 2 ).
|
|
DATA(res_s8) = find( val = str_s sub = `e` occ = -1 ).
|
|
DATA(res_s9) = find( val = str_s sub = `e` occ = -3 ).
|
|
|
|
"Specifying off and len
|
|
"Specifying a subarea in which a string is searched
|
|
DATA(res_s10) = find( val = str_s sub = `e` off = 5 ).
|
|
DATA(res_s11) = find( val = str_s sub = `e` off = 5 len = 7 ).
|
|
DATA(res_s12) = find( val = str_s sub = `e` len = 2 ).
|
|
|
|
out->write( data = res_s1 name = `res_s1` ).
|
|
out->write( |\n| ).
|
|
out->write( data = res_s2 name = `res_s2` ).
|
|
out->write( |\n| ).
|
|
out->write( data = res_s3 name = `res_s3` ).
|
|
out->write( |\n| ).
|
|
out->write( data = res_s4 name = `res_s4` ).
|
|
out->write( |\n| ).
|
|
out->write( data = res_s5 name = `res_s5` ).
|
|
out->write( |\n| ).
|
|
out->write( data = res_s6 name = `res_s6` ).
|
|
out->write( |\n| ).
|
|
out->write( data = res_s7 name = `res_s7` ).
|
|
out->write( |\n| ).
|
|
out->write( data = res_s8 name = `res_s8` ).
|
|
out->write( |\n| ).
|
|
out->write( data = res_s9 name = `res_s9` ).
|
|
out->write( |\n| ).
|
|
out->write( data = res_s10 name = `res_s10` ).
|
|
out->write( |\n| ).
|
|
out->write( data = res_s11 name = `res_s11` ).
|
|
out->write( |\n| ).
|
|
out->write( data = res_s12 name = `res_s12` ).
|
|
out->write( |\n| ).
|
|
|
|
"Demonstrating a false range to be searched
|
|
TRY.
|
|
DATA(res_s13) = find( val = str_s sub = `e` off = 5 len = 15 ).
|
|
CATCH cx_sy_range_out_of_bounds.
|
|
out->write( `The exception cx_sy_range_out_of_bounds was raised.` ).
|
|
ENDTRY.
|
|
|
|
***********************************************************************
|
|
|
|
out->write( zcl_demo_abap_aux=>heading( `21) Replacing Substrings in Strings Using REPLACE Statments` ) ).
|
|
|
|
DATA(str_t) = `abap ABAP abap`.
|
|
DATA(str_t1) = str_t.
|
|
|
|
"Simple REPLACE statement
|
|
"Omitting the FIRST OCCURRENCE and ALL OCCURRENCES OF additions means
|
|
"replacing the first occurrence by default.
|
|
REPLACE `ab` IN str_t1 WITH `##`.
|
|
|
|
out->write( data = str_t1 name = `str_t1` ).
|
|
out->write( |\n| ).
|
|
DATA(str_t2) = str_t.
|
|
|
|
"Addition SUBSTRING is optional; same effect as the statement above
|
|
REPLACE SUBSTRING `ab` IN str_t2 WITH `##`.
|
|
|
|
out->write( data = str_t2 name = `str_t2` ).
|
|
out->write( |\n| ).
|
|
DATA(str_t3) = str_t.
|
|
|
|
"Addition FIRST OCCURRENCE OF: Explicit specification to replace the
|
|
"first occurrence; same effect as the statements above
|
|
REPLACE FIRST OCCURRENCE OF `ab` IN str_t3 WITH `##`.
|
|
|
|
out->write( data = str_t3 name = `str_t3` ).
|
|
out->write( |\n| ).
|
|
DATA(str_t4) = str_t.
|
|
|
|
"Addition ALL OCCURRENCES OF: All occurrences are replaced
|
|
"Note that the replacement is case-sensitive by default.
|
|
REPLACE ALL OCCURRENCES OF `ab` IN str_t4 WITH `##`.
|
|
|
|
out->write( data = str_t4 name = `str_t4` ).
|
|
out->write( |\n| ).
|
|
DATA(str_t5) = str_t.
|
|
|
|
"Further additional options for advanced evaluation options
|
|
|
|
"IGNORING CASE addition: Making replacements case-insensitive
|
|
REPLACE ALL OCCURRENCES OF `ab`
|
|
IN str_t5 WITH `##`
|
|
IGNORING CASE.
|
|
|
|
out->write( data = str_t5 name = `str_t5` ).
|
|
out->write( |\n| ).
|
|
DATA(str_t6) = str_t.
|
|
|
|
"REPLACEMENT COUNT addition
|
|
REPLACE ALL OCCURRENCES OF `ab`
|
|
IN str_t6 WITH `##`
|
|
REPLACEMENT COUNT DATA(cnt_t7)
|
|
IGNORING CASE.
|
|
|
|
out->write( data = str_t6 name = `str_t6` ).
|
|
out->write( |\n| ).
|
|
out->write( data = cnt_t7 name = `cnt_t7` ).
|
|
out->write( |\n| ).
|
|
DATA(str_t8) = str_t.
|
|
|
|
"REPLACEMENT OFFSET and LENGTH additions
|
|
REPLACE FIRST OCCURRENCE OF `ap`
|
|
IN str_t8 WITH `##`
|
|
REPLACEMENT COUNT DATA(cnt_t9) "always 1 for replaced first occurrence
|
|
REPLACEMENT OFFSET DATA(off_t10)
|
|
REPLACEMENT LENGTH DATA(len_t11)
|
|
IGNORING CASE.
|
|
|
|
out->write( data = str_t8 name = `str_t8` ).
|
|
out->write( |\n| ).
|
|
out->write( data = cnt_t9 name = `cnt_t9` ).
|
|
out->write( |\n| ).
|
|
out->write( data = off_t10 name = `off_t10` ).
|
|
out->write( |\n| ).
|
|
out->write( data = len_t11 name = `len_t11` ).
|
|
out->write( |\n| ).
|
|
DATA(str_t12) = str_t.
|
|
|
|
"SECTION ... OF addition: Replacing within a specified area
|
|
REPLACE ALL OCCURRENCES OF `ap`
|
|
IN SECTION OFFSET 4 LENGTH 5
|
|
OF str_t12 WITH `##`
|
|
REPLACEMENT COUNT DATA(cnt_t13)
|
|
REPLACEMENT OFFSET DATA(off_t14)
|
|
REPLACEMENT LENGTH DATA(len_t15)
|
|
IGNORING CASE.
|
|
|
|
out->write( data = str_t12 name = `str_t12` ).
|
|
out->write( |\n| ).
|
|
out->write( data = cnt_t13 name = `cnt_t13` ).
|
|
out->write( |\n| ).
|
|
out->write( data = off_t14 name = `off_t14` ).
|
|
out->write( |\n| ).
|
|
out->write( data = len_t15 name = `len_t15` ).
|
|
out->write( |\n| ).
|
|
DATA(str_t16) = str_t.
|
|
|
|
"RESULTS additions with ...
|
|
"... ALL OCCURRENCES OF
|
|
"Note: The data object, which is declared inline here, is of type repl_result_tab.
|
|
REPLACE ALL OCCURRENCES OF `ap`
|
|
IN str_t16 WITH `##`
|
|
RESULTS DATA(tab_t17)
|
|
IGNORING CASE.
|
|
|
|
out->write( data = str_t16 name = `str_t16` ).
|
|
out->write( |\n| ).
|
|
out->write( data = tab_t17 name = `tab_t17` ).
|
|
out->write( |\n| ).
|
|
DATA(str_t18) = str_t.
|
|
|
|
"... FIRST OCCURRENCE OF
|
|
"Note: The data object, which is declared inline here, is of type repl_result.
|
|
REPLACE FIRST OCCURRENCE OF `ap`
|
|
IN str_t18 WITH `##`
|
|
RESULTS DATA(struc_t19)
|
|
IGNORING CASE.
|
|
|
|
out->write( data = str_t18 name = `str_t18` ).
|
|
out->write( |\n| ).
|
|
out->write( data = struc_t19 name = `struc_t19` ).
|
|
|
|
***********************************************************************
|
|
|
|
out->write( zcl_demo_abap_aux=>heading( `21) Position-Based Replacements with REPLACE SECTION ... OF` ) ).
|
|
|
|
DATA(str_u) = `abap ABAP abap`.
|
|
DATA(str_u1) = str_u.
|
|
|
|
"OFFSET and LENGTH specified
|
|
REPLACE SECTION OFFSET 5 LENGTH 4 OF str_u1 WITH `#`.
|
|
|
|
out->write( data = str_u1 name = `str_u1` ).
|
|
out->write( |\n| ).
|
|
DATA(str_u2) = str_u.
|
|
|
|
"Only OFFSET specified, LENGTH: up to the end of the string
|
|
REPLACE SECTION OFFSET 5 OF str_u2 WITH `#`.
|
|
|
|
out->write( data = str_u2 name = `str_u2` ).
|
|
out->write( |\n| ).
|
|
DATA(str_u3) = str_u.
|
|
|
|
"Only LENGTH specified, OFFSET: starting from the leftmost position
|
|
REPLACE SECTION LENGTH 6 OF str_u3 WITH `#`.
|
|
|
|
out->write( data = str_u3 name = `str_u3` ).
|
|
|
|
***********************************************************************
|
|
|
|
out->write( zcl_demo_abap_aux=>heading( `22) Replacements in Internal Tables with REPLACE ... IN TABLE` ) ).
|
|
|
|
DATA(tab_v) = VALUE string_table( ( `aZbzZ` ) ( `cdZze` ) ( `Zzzf` ) ( `ghz` ) ).
|
|
DATA(tab_v1) = tab_v.
|
|
|
|
"Replacing all occurrences in a table
|
|
"RESULTS addition: Storing information in an internal table of type repl_result_tab
|
|
REPLACE ALL OCCURRENCES OF `Z`
|
|
IN TABLE tab_v1
|
|
WITH `#`
|
|
RESULTS DATA(res_v2)
|
|
RESPECTING CASE.
|
|
|
|
out->write( data = tab_v1 name = `tab_v1` ).
|
|
out->write( |\n| ).
|
|
out->write( data = res_v2 name = `res_v2` ).
|
|
out->write( |\n| ).
|
|
DATA(tab_v3) = tab_v.
|
|
|
|
"Replacing the first occurrence in a table
|
|
"RESULTS addition: Storing information in a structure of type repl_result
|
|
REPLACE FIRST OCCURRENCE OF `Z`
|
|
IN TABLE tab_v3
|
|
WITH `#`
|
|
RESULTS DATA(res_v4)
|
|
RESPECTING CASE.
|
|
|
|
out->write( data = tab_v3 name = `tab_v3` ).
|
|
out->write( |\n| ).
|
|
out->write( data = res_v4 name = `res_v4` ).
|
|
out->write( |\n| ).
|
|
DATA(tab_v5) = tab_v.
|
|
|
|
"Restricting the search range in an internal table
|
|
REPLACE ALL OCCURRENCES OF `Z`
|
|
IN TABLE tab_v5
|
|
FROM 1 TO 2
|
|
WITH `#`
|
|
RESPECTING CASE.
|
|
|
|
out->write( data = tab_v5 name = `tab_v5` ).
|
|
out->write( |\n| ).
|
|
DATA(tab_v6) = tab_v.
|
|
|
|
"Offsets can be optionally specified (also only the offset of start or end line possible)
|
|
REPLACE ALL OCCURRENCES OF `Z`
|
|
IN TABLE tab_v6
|
|
FROM 1 OFFSET 3 TO 2 OFFSET 2
|
|
WITH `#`
|
|
RESPECTING CASE.
|
|
|
|
out->write( data = tab_v6 name = `tab_v6` ).
|
|
|
|
***********************************************************************
|
|
|
|
out->write( zcl_demo_abap_aux=>heading( `23) Replacing Substrings in Strings Using the String Function replace` ) ).
|
|
|
|
DATA(str_w) = `abap ABAP abap`.
|
|
|
|
"Note that here only the first occurrence is replaced.
|
|
DATA(str_w_1) = replace( val = str_w sub = `ap` with = `#` ).
|
|
|
|
"Making the search case-insensitive
|
|
DATA(str_w_2) = replace( val = str_w sub = `AB` with = `#` case = abap_false ).
|
|
|
|
"Setting occ
|
|
DATA(str_w_3) = replace( val = str_w sub = `ab` with = `#` occ = 2 case = abap_false ).
|
|
|
|
"Replacing all occurrences: Setting occ to 0
|
|
DATA(str_w_4) = replace( val = str_w sub = `ab` with = `#` occ = 0 case = abap_false ).
|
|
|
|
"Negative value for occ: Occurrences are counted from the right
|
|
DATA(str_w_5) = replace( val = str_w sub = `ab` with = `#` occ = -1 ).
|
|
|
|
"Setting off and len for determining a subarea for replacements
|
|
"Note: When using off/len, sub and occ cannot be specified.
|
|
"Specifying both off and len
|
|
DATA(str_w_6) = replace( val = str_w with = `#` off = 5 len = 3 ).
|
|
|
|
"Specifying only off (len is 0 by default)
|
|
DATA(str_w_7) = replace( val = str_w with = `#` off = 2 ).
|
|
|
|
"Note: When specifying only off and not specifying len or len = 0,
|
|
"replace works like insert
|
|
DATA(str_w_8) = insert( val = str_w sub = `#` off = 2 ).
|
|
|
|
"Specifying only len (off is 0 by default): First segment of length in len is replaced
|
|
DATA(str_w_9) = replace( val = str_w with = `#` len = 3 ).
|
|
|
|
"Special case
|
|
"- off: equal to the length of the string
|
|
"- len: not specified or 0
|
|
"- Result: Value specified for 'with' is appended to the end of the string
|
|
DATA(str_w_10) = replace( val = str_w with = `#` off = strlen( str_w ) ).
|
|
|
|
out->write( data = str_w_1 name = `str_w_1` ).
|
|
out->write( |\n| ).
|
|
out->write( data = str_w_2 name = `str_w_2` ).
|
|
out->write( |\n| ).
|
|
out->write( data = str_w_3 name = `str_w_3` ).
|
|
out->write( |\n| ).
|
|
out->write( data = str_w_4 name = `str_w_4` ).
|
|
out->write( |\n| ).
|
|
out->write( data = str_w_5 name = `str_w_5` ).
|
|
out->write( |\n| ).
|
|
out->write( data = str_w_6 name = `str_w_6` ).
|
|
out->write( |\n| ).
|
|
out->write( data = str_w_7 name = `str_w_7` ).
|
|
out->write( |\n| ).
|
|
out->write( data = str_w_8 name = `str_w_8` ).
|
|
out->write( |\n| ).
|
|
out->write( data = str_w_9 name = `str_w_9` ).
|
|
out->write( |\n| ).
|
|
out->write( data = str_w_10 name = `str_w_10` ).
|
|
|
|
***********************************************************************
|
|
|
|
out->write( zcl_demo_abap_aux=>heading( `Pattern-Based Searching and Replacing in Strings` ) ).
|
|
out->write( `24) Simple Pattern-Based Searching ` &&
|
|
`Using Logical Operators` ).
|
|
|
|
DATA(str_x) = `abc_def_ghi`.
|
|
|
|
"CP (conforms to pattern)
|
|
"*: Any character sequence (including blanks).
|
|
"+: Any character (only one character, including blanks).
|
|
"#: Escaping symbol. The following character is marked for an exact
|
|
"comparison.
|
|
"Note: Patterns are not case sensitive except for characters marked
|
|
"by #. If a pattern is found, the system variable sy-fdpos returns
|
|
"the offset of the first finding. Otherwise, it contains the length
|
|
"of the searched string.
|
|
IF str_x CP `*f#_*`.
|
|
out->write( |CP: The string covers the pattern. |
|
|
&& |The offset is { sy-fdpos }.| ).
|
|
ELSE.
|
|
out->write( |CP: The string does not cover the pattern. |
|
|
&& |The length of the string is { sy-fdpos }.| ).
|
|
ENDIF.
|
|
|
|
out->write( |\n| ).
|
|
|
|
"NP (does not conform to pattern)
|
|
IF str_x NP `i+`.
|
|
out->write( |NP: The string does not cover the pattern. |
|
|
&& |The length of the string is { sy-fdpos }.| ).
|
|
ELSE.
|
|
out->write( |NP: The string covers the pattern. |
|
|
&& |The offset is { sy-fdpos }.| ).
|
|
ENDIF.
|
|
|
|
***********************************************************************
|
|
|
|
out->write( zcl_demo_abap_aux=>heading( `25) Complex Searching Using ` &&
|
|
`Regular Expressions` ) ).
|
|
|
|
DATA(str_y) = `Cathy's black cat was fast asleep on the mat. ` &&
|
|
`Later that day, the cat played with Matt.`.
|
|
|
|
"Using string functions
|
|
|
|
"Determining the position of the first finding
|
|
"here, parameter occ is 1 by default
|
|
DATA(off_y1) = find( val = str_y pcre = `at.` ).
|
|
|
|
"Determining the number of findings
|
|
"Considers all 'a' characters not followed by 't',
|
|
"all 'at' plus 'att'
|
|
DATA(cnt_y2) = count( val = str_y pcre = `at*` ).
|
|
"Considers all 'at' plus 'att' and so on
|
|
DATA(cnt_y3) = count( val = str_y pcre = `at+` ).
|
|
|
|
"String function match
|
|
"Extracting a substring matching a given pattern
|
|
DATA(str_y_email1) = `The email address is jon.doe@email.com.`.
|
|
DATA(str_y4) = match( val = str_y_email1
|
|
pcre = `\w+(\.\w+)*@(\w+\.)+(\w{2,4})` ).
|
|
|
|
"Predicate function matches
|
|
"Checking a string if it matches a given pattern
|
|
DATA(str_y_email2) = `jon.doe@email.com`.
|
|
|
|
IF matches( val = str_y_email2
|
|
pcre = `\w+(\.\w+)*@(\w+\.)+(\w{2,4})` ).
|
|
DATA(str_y5) = |{ str_y_email2 } is a valid email address.|.
|
|
ELSE.
|
|
str_y5 = |{ str_y_email2 } is not a valid email address.|.
|
|
ENDIF.
|
|
|
|
"Example with a false email
|
|
DATA(str_y_email3) = `jon.doe@email.abcdef`.
|
|
|
|
IF matches( val = str_y_email3
|
|
pcre = `\w+(\.\w+)*@(\w+\.)+(\w{2,4})` ).
|
|
DATA(str_y6) = |{ str_y_email3 } is a valid email address.|.
|
|
ELSE.
|
|
str_y6 = |{ str_y_email3 } is not a valid email address.|.
|
|
ENDIF.
|
|
|
|
"Examples with the FIND statement
|
|
"Storing submatches in variables.
|
|
"Pattern: anything before and after ' on '
|
|
FIND PCRE `(.*)\son\s(.*)` IN str_y
|
|
SUBMATCHES DATA(subm_y7) DATA(subm_y8)
|
|
IGNORING CASE.
|
|
|
|
"Determining the number of letters in a string
|
|
FIND ALL OCCURRENCES OF PCRE `[A-Za-z]`
|
|
IN str_y
|
|
MATCH COUNT DATA(cnt_y9).
|
|
|
|
"Extracting all findings of a certain pattern in a string and
|
|
"storing them in an internal table
|
|
DATA tab_y10 TYPE string_table.
|
|
|
|
"Pattern: An 'a' followed by any two characters
|
|
FIND ALL OCCURRENCES OF PCRE `a..` IN str_y
|
|
RESULTS DATA(res_y11).
|
|
|
|
"The internal table includes the offset and length information of the individual findings.
|
|
"The substrings are extracted from the original string based on that information and
|
|
"added to an internal table of type string.
|
|
LOOP AT res_y11 ASSIGNING FIELD-SYMBOL(<fs_y>).
|
|
APPEND substring( val = str_y off = <fs_y>-offset len = <fs_y>-length ) TO tab_y10.
|
|
ENDLOOP.
|
|
|
|
"Searching in an internal table and retrieving line, offset, length information
|
|
DATA(tab_y12) = VALUE string_table( ( `Cathy's black cat on the mat played with the friend of Matt.` )
|
|
( `Later that day, the cat played with Matt.` ) ).
|
|
|
|
"Pattern: any character + 'y' followed by any character that is not a word character
|
|
"Only the first occurrence is searched. The search is specified as case-insensitive (which is not relevant here).
|
|
FIND FIRST OCCURRENCE OF PCRE `.y\W` IN TABLE tab_y12
|
|
MATCH LINE DATA(line_y13)
|
|
MATCH OFFSET DATA(off_y14)
|
|
MATCH LENGTH DATA(len_y15)
|
|
IGNORING CASE.
|
|
|
|
"Pattern: any character + 'y' followed by any character that is not a word character
|
|
"Here, all occurrences are searched and the result is stored in an internal table specified
|
|
"after the RESULTS addition. Since a group is included in the PCRE pattern denoted by the
|
|
"parentheses (\W), the resulting internal table includes entries in the 'submatches'
|
|
"component holding offset/length information for the particular match.
|
|
FIND ALL OCCURRENCES OF PCRE `.y(\W)` IN TABLE tab_y12
|
|
RESULTS DATA(res_y16)
|
|
IGNORING CASE.
|
|
|
|
"Extracting all findings of certain patterns in a string and
|
|
"storing them in an internal table; the capturing groups are
|
|
"also evaluated
|
|
DATA tab_y17 TYPE string_table.
|
|
DATA(str_y18) = `az.ay.bx.bw.cv.cu.dt.ds.ar.bq`.
|
|
|
|
FIND ALL OCCURRENCES OF PCRE `(a.)|(b.)|(c.)`
|
|
IN str_y18
|
|
RESULTS DATA(res_y19)
|
|
IGNORING CASE.
|
|
|
|
LOOP AT res_y19 ASSIGNING FIELD-SYMBOL(<fs_y20>).
|
|
LOOP AT <fs_y20>-submatches ASSIGNING FIELD-SYMBOL(<fs_y21>).
|
|
IF <fs_y21>-offset <> -1.
|
|
APPEND |Substring "{ substring( val = str_y18 off = <fs_y21>-offset len = <fs_y21>-length ) }" found, capturing group { sy-tabix }| TO tab_y17.
|
|
ENDIF.
|
|
ENDLOOP.
|
|
ENDLOOP.
|
|
|
|
out->write( data = off_y1 name = `off_y1` ).
|
|
out->write( |\n| ).
|
|
out->write( data = cnt_y2 name = `cnt_y2` ).
|
|
out->write( |\n| ).
|
|
out->write( data = cnt_y3 name = `cnt_y3` ).
|
|
out->write( |\n| ).
|
|
out->write( data = str_y4 name = `str_y4` ).
|
|
out->write( |\n| ).
|
|
out->write( data = str_y5 name = `str_y5` ).
|
|
out->write( |\n| ).
|
|
out->write( data = str_y6 name = `str_y6` ).
|
|
out->write( |\n| ).
|
|
out->write( data = subm_y7 name = `subm_y7` ).
|
|
out->write( |\n| ).
|
|
out->write( data = subm_y8 name = `subm_y8` ).
|
|
out->write( |\n| ).
|
|
out->write( data = cnt_y9 name = `cnt_y9` ).
|
|
out->write( |\n| ).
|
|
out->write( data = tab_y10 name = `tab_y10` ).
|
|
out->write( |\n| ).
|
|
out->write( data = line_y13 name = `line_y13` ).
|
|
out->write( |\n| ).
|
|
out->write( data = off_y14 name = `off_y14` ).
|
|
out->write( |\n| ).
|
|
out->write( data = len_y15 name = `len_y15` ).
|
|
out->write( |\n| ).
|
|
out->write( data = res_y16 name = `res_y16` ).
|
|
out->write( |\n| ).
|
|
out->write( data = tab_y17 name = `tab_y17` ).
|
|
|
|
***********************************************************************
|
|
|
|
out->write( zcl_demo_abap_aux=>heading( `26) Replacing Using Regular Expressions` ) ).
|
|
|
|
DATA(str_z) = `Cathy's black cat was fast asleep on the mat. ` &&
|
|
`Later that day, the cat played with Matt.`.
|
|
|
|
"Considers all 'a' characters not followed by 't',
|
|
"all 'at' plus 'att'
|
|
"occ = 0 -> replaces all occurrences
|
|
DATA(str_z1) = replace( val = str_z
|
|
pcre = `at*`
|
|
with = `#`
|
|
occ = 0 ).
|
|
|
|
"Considers all 'at' plus 'att'
|
|
DATA(str_z2) = replace( val = str_z
|
|
pcre = `at+`
|
|
with = `#`
|
|
occ = 0 ).
|
|
|
|
"Replaces 2 'e' characters in a row
|
|
DATA(str_z3) = replace( val = str_z
|
|
pcre = `e{2}`
|
|
with = `#`
|
|
occ = 0 ).
|
|
|
|
"Replaces 'ay'. Preceding d is optional ('day' is replaced too)
|
|
DATA(str_z4) = replace( val = str_z
|
|
pcre = `d?ay`
|
|
with = `#`
|
|
occ = 0 ).
|
|
|
|
"Subgroup specified, replacement happens if 'at' is followed
|
|
"by 'h' or 't'
|
|
DATA(str_z5) = replace( val = str_z
|
|
pcre = `at(h|t)`
|
|
with = `#`
|
|
occ = 0 ).
|
|
|
|
"Replaces 'at' when followed by any whitespace character
|
|
DATA(str_z6) = replace( val = str_z
|
|
pcre = `at\s`
|
|
with = `#`
|
|
occ = 0 ).
|
|
|
|
"Replacement starts at beginning of string that is followed by 'c'
|
|
"Marked as not case sensitive
|
|
"Instead of ^, you could also use \A
|
|
DATA(str_z7) = replace( val = str_z
|
|
pcre = `^c`
|
|
with = `#`
|
|
case = abap_false ).
|
|
|
|
"Replacement starts at end of string
|
|
"Instead of $, you could also use \Z
|
|
DATA(str_z8) = replace( val = str_z
|
|
pcre = `$`
|
|
with = ` Awesome!` ).
|
|
|
|
"Replaces words starting with 'ma', ending with another character
|
|
DATA(str_z9) = replace( val = str_z
|
|
pcre = `\bma.\b`
|
|
with = `#`
|
|
case = abap_false
|
|
occ = 0 ).
|
|
|
|
"Replaces the beginning of words with 'ma' followed by another
|
|
"character.
|
|
"Marked as not case sensitive, hence 'Mat' is considered, too.
|
|
DATA(str_z10) = replace( val = str_z
|
|
pcre = `\bma.`
|
|
with = `#`
|
|
case = abap_false
|
|
occ = 0 ).
|
|
|
|
"Replaces a specified set of literals; if 'case = abap_false'
|
|
"is not specified, case sensitivity is respected
|
|
DATA(str_z11) = replace( val = str_z
|
|
pcre = `[eC'.,]`
|
|
with = `#`
|
|
occ = 0 ).
|
|
|
|
"Replaces a specified value range
|
|
DATA(str_z12) = replace( val = str_z
|
|
pcre = `[a-eA-C0-9]`
|
|
with = `#`
|
|
occ = 0 ).
|
|
|
|
"Replaces a specified value range. The example is the negation
|
|
"of the previous example.
|
|
DATA(str_z13) = replace( val = str_z
|
|
pcre = `[^a-eA-C0-9]`
|
|
with = `#`
|
|
occ = 0 ).
|
|
|
|
DATA(str_zb) = `<p><i>Date:</i> 12/16/2022</p>` &&
|
|
`<br><p>Time: 10:30</p>`.
|
|
|
|
"Replacements considering subgroups
|
|
"Example switches the date format from US to European
|
|
"Sequences of digits are specified as subgroups followed by /
|
|
DATA(str_z15) = replace( val = str_zb
|
|
pcre = `(\d+)/(\d+)/`
|
|
with = `$2.$1.` ).
|
|
|
|
"Regex pitfall: Watch greediness when using PCRE expressions
|
|
"Example: Replacing all HTML tags in a string
|
|
DATA(str_z16) = replace( val = str_zb
|
|
pcre = `<.*>`
|
|
with = ``
|
|
occ = 0 ). "Whole string replaced
|
|
|
|
"The following pattern considers '<' not followed by '>' which is
|
|
"specified in a negated definition for a single character in the
|
|
"brackets. Then '*' greedily, matches anything until the next '>'.
|
|
DATA(str_z17) = replace( val = str_zb
|
|
pcre = `<[^>]*>`
|
|
with = ``
|
|
occ = 0 ).
|
|
|
|
"Positive lookahead: Replaces colons followed by digits
|
|
DATA(str_z18) = replace( val = str_zb
|
|
pcre = `:(?=\d+)`
|
|
with = `.`
|
|
occ = 0 ).
|
|
|
|
"Negative lookahead: Removes colons not followed by digits
|
|
":(?!(\d+))
|
|
DATA(str_z19) = replace( val = str_zb
|
|
pcre = `:(?!\d+)`
|
|
with = ``
|
|
occ = 0 ).
|
|
|
|
"Positive Lookbehind: Replaces a digit preceded by a blank
|
|
DATA(str_z20) = replace( val = str_zb
|
|
pcre = `(?<=\s)\d`
|
|
with = `0`
|
|
occ = 0 ).
|
|
|
|
"Negative lookbehind: Determines the position before closing p tags
|
|
"not preceded by 4 digits
|
|
DATA(str_z21) = replace( val = str_zb
|
|
pcre = `(?<!\d{4})(<\/p>)`
|
|
with = `:00$1`
|
|
occ = 0 ).
|
|
|
|
DATA(str_zc) = `ab apppc app`.
|
|
|
|
"Greedy search
|
|
"The pattern matches anything before 'p'. The matching is carried
|
|
"out as often as possible. Hence, in this example the match
|
|
"stretches until the end of the string since 'p' is the final
|
|
"character, i. e. this 'p' and anything before is replaced).
|
|
DATA(str_z23) = replace( val = str_zc
|
|
pcre = `.*p`
|
|
with = `#` ).
|
|
|
|
"Non-greedy search (denoted by '?' below)
|
|
"The pattern matches anything before 'p'. The matching proceeds
|
|
"until the first 'p' is found and does not go beyond (matching as
|
|
"few as possible). Hence, the first found 'p' including the content
|
|
"before is replaced.
|
|
DATA(str_z24) = replace( val = str_zc
|
|
pcre = `.*?p`
|
|
with = `#` ).
|
|
|
|
"Replacements with subgroups
|
|
"Replaces 'PP' (case-insensitive) with '#', the content before and
|
|
"after 'PP' is switched
|
|
DATA(str_z25) = replace( val = str_zc
|
|
pcre = `(.*?)PP(.*)`
|
|
with = `$2#$1`
|
|
case = abap_false ).
|
|
|
|
"REPLACE statement: Changing the source field directly
|
|
REPLACE PCRE `(.*?)PP(.*)` IN str_zc WITH `$2#$1` IGNORING CASE.
|
|
|
|
"Replacements in internal tables
|
|
DATA(itab_z) = VALUE string_table( ( `Cathy's black cat was fast asleep on the mat.` )
|
|
( `Later that day, the cat played with Matt.` )
|
|
( `How about that?` ) ).
|
|
|
|
"Replaces all 'th' occurrences in words beginning with 'th'
|
|
REPLACE ALL OCCURRENCES OF PCRE `\bth`
|
|
IN TABLE itab_z WITH `#`
|
|
REPLACEMENT COUNT DATA(cnt_z26)
|
|
IGNORING CASE .
|
|
|
|
out->write( data = |Original str_z: { str_z }\n| ).
|
|
out->write( |\n| ).
|
|
out->write( data = str_z1 name = `str_z1` ).
|
|
out->write( |\n| ).
|
|
out->write( data = str_z2 name = `str_z2` ).
|
|
out->write( |\n| ).
|
|
out->write( data = str_z3 name = `str_z3` ).
|
|
out->write( |\n| ).
|
|
out->write( data = str_z4 name = `str_z4` ).
|
|
out->write( |\n| ).
|
|
out->write( data = str_z5 name = `str_z5` ).
|
|
out->write( |\n| ).
|
|
out->write( data = str_z6 name = `str_z6` ).
|
|
out->write( |\n| ).
|
|
out->write( data = str_z7 name = `str_z7` ).
|
|
out->write( |\n| ).
|
|
out->write( data = str_z8 name = `str_z8` ).
|
|
out->write( |\n| ).
|
|
out->write( data = str_z9 name = `str_z9` ).
|
|
out->write( |\n| ).
|
|
out->write( data = str_z10 name = `str_z10` ).
|
|
out->write( |\n| ).
|
|
out->write( data = str_z11 name = `str_z11` ).
|
|
out->write( |\n| ).
|
|
out->write( data = str_z12 name = `str_z12` ).
|
|
out->write( |\n| ).
|
|
out->write( data = str_z3 name = `str_z13` ).
|
|
out->write( |\n| ).
|
|
out->write( data = |Original str_zb: { str_zb }\n| ).
|
|
out->write( |\n| ).
|
|
out->write( data = str_z15 name = `str_z15` ).
|
|
out->write( |\n| ).
|
|
out->write( data = str_z16 name = `str_z16` ).
|
|
out->write( |\n| ).
|
|
out->write( data = str_z17 name = `str_z17` ).
|
|
out->write( |\n| ).
|
|
out->write( data = str_z18 name = `str_z18` ).
|
|
out->write( |\n| ).
|
|
out->write( data = str_z19 name = `str_z19` ).
|
|
out->write( |\n| ).
|
|
out->write( data = str_z20 name = `str_z20` ).
|
|
out->write( |\n| ).
|
|
out->write( data = str_z21 name = `str_z21` ).
|
|
out->write( |\n| ).
|
|
out->write( data = |Original str_zc: { str_zc }\n| ).
|
|
out->write( |\n| ).
|
|
out->write( data = str_z23 name = `str_z23` ).
|
|
out->write( |\n| ).
|
|
out->write( data = str_z24 name = `str_z24` ).
|
|
out->write( |\n| ).
|
|
out->write( data = str_z25 name = `str_z25` ).
|
|
out->write( |\n| ).
|
|
out->write( data = str_zc name = `str_zc` ).
|
|
out->write( |\n| ).
|
|
out->write( data = itab_z name = `itab_z` ).
|
|
out->write( |\n| ).
|
|
out->write( data = |Number of replacements in itab (cnt_z26): { cnt_z26 }| ).
|
|
|
|
***********************************************************************
|
|
|
|
out->write( zcl_demo_abap_aux=>heading( `27) Excursion: System Classes for Regular Expressions` ) ).
|
|
|
|
"Searching for all occurrences
|
|
DATA(some_string) = `a1 # B2 ? cd . E3`.
|
|
|
|
"Creating a regex instance for PCRE regular expressions
|
|
"In the example, regex_inst has the type ref to cl_abap_regex.
|
|
DATA(regex_inst) = cl_abap_regex=>create_pcre( pattern = `\D\d` "any-non digit followed by a digit
|
|
ignore_case = abap_true ).
|
|
|
|
"Creating an instance of CL_ABAP_MATCHER using the method CREATE_MATCHER of the class CL_ABAP_REGEX
|
|
DATA(matcher_1) = regex_inst->create_matcher( text = some_string ).
|
|
|
|
"Searching for all occurrences using the 'find_all' method
|
|
"In the example, result has the type match_result_tab containing the findings.
|
|
DATA(result1) = matcher_1->find_all( ).
|
|
|
|
out->write( data = result1 name = `result1` ).
|
|
out->write( |\n| ).
|
|
|
|
"You can also use method chaining to save lines of code
|
|
DATA(result2) = cl_abap_regex=>create_pcre( pattern = `\s\w` "any blank followed by any word character
|
|
ignore_case = abap_true )->create_matcher( text = some_string )->find_all( ).
|
|
|
|
out->write( data = result2 name = `result2` ).
|
|
out->write( |\n| ).
|
|
|
|
"Retrieving submatches using the 'get_submatch' method
|
|
DATA str_tab_reg_find TYPE string_table.
|
|
|
|
DATA(matcher_2) = cl_abap_regex=>create_pcre( pattern = 'A(.*?)B(.*?)C(.*?)'
|
|
ignore_case = abap_false )->create_matcher( text = 'A.12az.B.34by.C.56cx.D.78dw.E' ).
|
|
|
|
IF matcher_2->match( ).
|
|
DO.
|
|
TRY.
|
|
APPEND matcher_2->get_submatch( sy-index ) TO str_tab_reg_find.
|
|
CATCH cx_sy_invalid_submatch cx_sy_no_current_match.
|
|
EXIT.
|
|
ENDTRY.
|
|
ENDDO.
|
|
ENDIF.
|
|
|
|
out->write( data = str_tab_reg_find name = `str_tab_reg_find` ).
|
|
|
|
ENDMETHOD.
|
|
ENDCLASS.
|