Andre Fischer
September 5, 2018 4 minute read
How to split a string into 4 strings of equal length in ABAP?
221950,993
This question sounds trivial, doesn’t it?
I ran into this when developing the new tasklist for the mass maintenance of OData services (see my blog Custom tasklist for OData service mass maintenance).
Since I am calling API’s that do not return the root cause of an error I wrote some code that retrieved the long text of the original error.
The problem was then that I had to call a method to add a T100 message to a log file that required 4 parameters of type CHAR50.
So I had to cut the string into 4 pieces each having the length of 50 characters.
Let’s have a look what would happen if the incoming string has a length of 102 characters.
First approach: CALL FUNCTION ‘SWA_STRING_SPLIT’
First I tried the function module ‘SWA_STRING_SPLIT’ that takes a string and the desired length of the substring as an Input parameter. The split string is returned via the table lt_string_comp.
CALL FUNCTION 'SWA_STRING_SPLIT'EXPORTING
input_string = lv_longtext "string to be splitmax_component_length = 50
TABLES
string_components = lt_string_comp.
You then still have the problem to find out the number of table entries and you cannot access the fourth table entry lt_string_comp[ 4 ] if the table has only three entries if the string has a length of 102 characters.
Second Approach: Use substring
The built in function substring has the disadvantage that it throws an error of type cx_sy_range_out_of_bounds if it would reach the statement
DATA(lv3) = substring( val = lv_longtext off = 100 len = 50 ).in case the string contained in lv_longtext has a length of 102 characters.
DATA: lv_longtext TYPE char200....
CATCH /iwfnd/cx_cof INTO DATA(lx_cof).lv_longtext = lx_cof->get_longtext( ).TRY.DATA(lv1) = substring( val = lv_longtext off = 0 len = 50 ).DATA(lv2) = substring( val = lv_longtext off = 50 len = 50 ).DATA(lv3) = substring( val = lv_longtext off = 100 len = 50 ).DATA(lv4) = substring( val = lv_longtext off = 150 len = 50 ).CATCH cx_sy_range_out_of_bounds INTO DATA(lx_too_long).WRITE : / lx_too_long->get_text( ).
ENDTRY.Third Approach: Use old-fashioned ABAP syntax
Though it is not recommended the following code works like a charm. If the string has a length of 102 characters lv7 would contain 2 characters and lv8 would simply be intial.
DATA(lv5) = lv_longtext(50).DATA(lv6) = lv_longtext+50(50).DATA(lv7) = lv_longtext+100(50).DATA(lv8) = lv_longtext+150(50).Fourth approach: Use cl_message_helper=>set_msg_vars_for_clike
Another option was mentioned by Matthew Billingham as a comment to this blog. By calling the method set_msg_vars_for_clike of class cl_message_helper you get four strings of length 50 characters as well.
This method under the hood uses the old fashioned ABAP syntax
MOVE c200+offset(50) TO sy-msgv2.
as well.
It in addition offers lots of other useful methods as well.
Final approach: Use a structure
The most flexible approach in my opinion (kudos go to my colleagues from the SAP Gateway runtime development team) is using a structure
In the following I move the long text to a structure with 4 fields of length 50 characters each.
As a result error messages longer than 200 characters are truncated but no exception is thrown opposed to using substring.
And it does not make use of out of date ABAP coding style.
Moreover you would be able to define a structure with fields that have different lengths, say 10, 24, 40 and 5 characters. A string moved to this structure would be split approriately without having to look for exceptions whose handling is time consuming and not needed in this case.
TYPES: BEGIN OF ty_longtext,msgv1(50),
msgv2(50),
msgv3(50),
msgv4(50),
END OF ty_longtext.DATA: ls_longtext TYPE ty_longtext....
CATCH /iwfnd/cx_cof INTO DATA(lx_cof).ls_longtext = lx_cof->get_longtext( )."add a t100 message
if_stctm_task~pr_log->add_t100(
EXPORTING
iv_msgty = 'E'
iv_msgid = '/IWFND/COD'
iv_msgno = '312'
iv_msgv1 = CONV #( ls_longtext-msgv1 )iv_msgv2 = CONV #( ls_longtext-msgv2 )iv_msgv3 = CONV #( ls_longtext-msgv3 )iv_msgv4 = CONV #( ls_longtext-msgv4 )).
Simple test report
If you want to play around I have created the following test report that shows four of the five approaches described above.
*&---------------------------------------------------------------------*
*& Report z_split_string
*&---------------------------------------------------------------------*
*&
*&---------------------------------------------------------------------*
REPORT z_split_string.DATA: lv_teststring TYPE string.DATA: lv_longtext TYPE char200.TYPES: BEGIN OF ty_longtext,msgv1(50),
msgv2(50),
msgv3(50),
msgv4(50),
END OF ty_longtext.DATA: ls_longtext TYPE ty_longtext.lv_teststring = '0123456789'. "10 characterslv_teststring = lv_teststring && lv_teststring. "20 characterslv_teststring = lv_teststring && lv_teststring. "40 characterslv_teststring = lv_teststring && lv_teststring. "80 characterslv_teststring = lv_teststring && '0123456789' && '012345678901' . "102 charactersDATA(length) = strlen( lv_teststring ).lv_longtext = lv_teststring.ls_longtext = lv_teststring.TRY.DATA(lv1) = substring( val = lv_longtext off = 0 len = 50 ).DATA(lv2) = substring( val = lv_longtext off = 50 len = 50 ).DATA(lv3) = substring( val = lv_longtext off = 100 len = 50 ).DATA(lv4) = substring( val = lv_longtext off = 150 len = 50 ).CATCH cx_sy_range_out_of_bounds INTO DATA(lx_too_long).data(lv_error_lx_too_long) = lx_too_long->get_text( ).ENDTRY.DATA(lv5) = lv_longtext(50).DATA(lv6) = lv_longtext+50(50).DATA(lv7) = lv_longtext+100(50).DATA(lv8) = lv_longtext+150(50).cl_message_helper=>set_msg_vars_for_clike( lv_longtext ).data(out) = cl_demo_output=>new( ).
out->write( : data = lv_error_lx_too_long ),data = '********************************' ),
data = 'use of substring' ),
data = lv1 ),
data = lv2 ),
data = lv3 ),
data = lv4 ),
data = 'old ABAP syntax' ),
data = lv5 ),
data = lv6 ),
data = lv7 ),
data = lv8 ),
data = 'string moved to structure' ),
data = ls_longtext-msgv1 ),data = ls_longtext-msgv2 ),data = ls_longtext-msgv3 ),data = ls_longtext-msgv4 ),data = 'use cl_message_helper' ),
data = sy-msgv1 ),
data = sy-msgv2 ),
data = sy-msgv3 ),
data = sy-msgv4
)->display( ).
Substring access (offset = 100, length = 50) to a data object of the size 102 exceeds valid boundaries.
use of substring
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
old ABAP syntax
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
string moved to structure
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
use cl_message_helper
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
FollowLikeRSS Feed
Alert Moderator
Assigned Tags
ABAP Development
SAP Gateway
Similar Blog Posts
The ABAP REDUCE Operator | A Tutorial for 2020
By Brandon CaulfieldSep 12, 2020
SQL Script for ABAP Managed Database Procedures(AMDP)-Code pushdown for a better performance!
By Santhosini KApr 14, 2021
How to retrieve the last character of a string in ABAP - definitive edition
By Frederik HudakJan 18, 2020
Related Questions
String operation in ABAP
By Former MemberNov 21, 2008
reverse a string
By Former MemberJul 14, 2005
Unable to SPLIT string after Read Dataset from Application Server
By Former MemberJun 18, 2010
22 Comments
Matthew Billingham
September 5, 2018 at 10:33 am
DATA(my_text) = 'Text to put into upto 4 char50 variables'.
cl_message_helper=>set_msg_vars_for_clike( my_text ).
WRITE / : sy-msgv1, sy-msgv2, sy-msgv3, sy-msgv4.
Like 6
Reply
Alert Moderator
Share
Andre Fischer
Blog Post Author
September 5, 2018 at 11:30 am
Hi Matthew,
thanks for pointing me to this option. I therefore changed the description for the approach using a structure from ""the best..." to "the most flexible approach". ;-).
Best Regards,
Andre
Like 0
Reply
Alert Moderator
Share
Matthew Billingham
September 5, 2018 at 12:40 pm
It’s more flexible if you’re wishing to do a quick concatenation, and the structure won’t change. This approach was used quite often pre-unicode. The problem that can arise is if a structure were to change so that it incorporated a non-clike field. It just doesn’t work then.
Looking at your problem as stated (and without knowing the full details obviously), if I’d encountered it, I’d have looked here:
The problem was then that I had to call a method to add a T100 message to a log file that required 4 parameters of type CHAR50.
The solution (if possible) would be to add a method so a string can be added to the log file. By doing this you have simpler calling code, and you’ve made your logging class more powerful.
Another hint -> as Horst Keller explains the ABAP documentation uses the class CL_DEMO_OUTPUT for sample code. You might like to look at that.
btw, SAP’s own ABAP Guidelines and DSAG’s latest best practice document, speak against using prefixes as type indicators such as l, s etc. Especially as not one of the variables in your example program is, in fact, local…
Like 1
Reply
Alert Moderator
Share
Andre Fischer
Blog Post Author
September 5, 2018 at 12:59 pm
Hi Matthew,
the class CL_DEMO_OUTPUT is nice but I am not allowed to use it in SAP production code since it has been released for demo purposes only.
Unfortunately I am not the owner of the logging class, but I will ask the colleagues what they can do.
Regards,
Andre
Like 0
Reply
Alert Moderator
Share
Matthew Billingham
...