Monday, 20 January 2020

How to retrieve the last character of a string in ABAP – definitive edition

Many of the resources we have on ABAP might be old, but they still frequently show up on top positions of search results. I encourage you to correct incorrect information you stumble upon, even many years later.

Here is my attempt to thoroughly solve a trivial problem I needed reminding about this week – retrieving the last character of a string.

My analysis will be presented in the form of a contest between the respondents to the same question asked on SAP Q&A in 2007, with some measurements at the end. Let’s see how the answers fare in 2020. There were seven proposed solutions, but first…

The problem specification

I need to get the last character of the string, like this…

‘AAAAAAAA BBBB 1 QQQQQQQQ 2’.

i need to take the last letter (2) to do more things b4.

I’m thinking to rotate the string and take the first letter, but i think will exist a FM that do my requirement.

The contenders


Amole

Hi,

use below logic

str = ‘test’.

data a type i.

a = strlen(str).

write str(a).

Regards

Amole

Verdict

Amole’s solution was voted best answer and highlighted in green. I reluctantly copy-pasted the code into a report.

The code does not compile. After fixing a couple of syntax errors, I ran the report to see it print out test, which is not the last character of the word test.

When cleaned up, you can easily see that the code always prints out the original string:

report zfh.

data(str) = 'test'.

data(len) = strlen( str ).
write str(len).

" this is equal to
write str+0(len).

" which is equal to
write str.

The author of the question mentions in a comment that they “like a lot the amole solution”. I’m not sure how to feel about that.

Rich Heilman

Lots of ways to do this. another one would be to use the function module REVERSE_STRING, or STRING_REVERSE. It is something like that. Anyway, from the name, you can guess what it does, then all you need to do is look at the first letter of the string using an offset.

Verdict

The algorithm proposed by Rich is correct. As for the function module, it’s the second one:

FUNCTION STRING_REVERSE
  IMPORTING
    VALUE(STRING) TYPE ANY
    VALUE(LANG) TYPE ANY
  EXPORTING
    VALUE(RSTRING) TYPE ANY
  EXCEPTIONS
    TOO_SMALL.

I especially like the lang parameter here, really makes you wonder. So if you are too, this function module will count characters slightly differently in Thai. I choose to forget about this particular fact and hope that strlen does return the universally agreed-upon lengths of characters on unicode systems. I would actually like to know if I’m right about this. Feel free to let me know in the comments.

The solution gets minus points in 2020 where clean code is a thing for relying on untyped parameters and legacy exception handling. Using a static utility method would be a much better choice today.

Also, it doesn’t work if used with the data type string, only on fixed-length character types.

SAP ABAP Tutorials and Materials, SAP ABAP Learning, SAP ABAP Guides, SAP ABAP Online Exam, SAP ABAP Exam Prep

Given the simplicity of the problem we’re trying to solve, this is a gotcha I wouldn’t expect to encounter. The parameter claims it could be anything!

I’m sorry Rich, but I have to disqualify you. But since you still work in SAP 13 years later, it might be fun for you to reminisce on how much changed since then in the comments section.

Prabhu

name = ‘PRABHU’.

n = strlen(name).

n = n – 1. (n = 5)

output = name+n(1) = U.

Regards

Prabhu

Verdict

Due to the unfortunate mixing of explanations and code without actually using comments, Prahbu’s solution does not compile and also loses some points for readability. But I can understand what he means and the algorithm is correct.

Former Member #1


one long way is

first use STRING_LENGTH FM , then subtract 1 from length

then use STRING_SPLIT_AT_POSITION and pass the length previously calculated

Verdict

Plus point for correct algorithm. #1’s proposed solution would look something like this:

report zfh.

data: string type string value 'ABCD',
      len    type i,
      result   type string.

call function 'STRING_LENGTH'
  exporting
    string = string
  importing
    length = len.

call function 'STRING_SPLIT_AT_POSITION'
  exporting
    string  = string
    pos     = len - 1
  importing
    string2 = result.

Unfortunately,

SAP ABAP Tutorials and Materials, SAP ABAP Learning, SAP ABAP Guides, SAP ABAP Online Exam, SAP ABAP Exam Prep

these function modules also do not work with strings. I’ve already explained my concerns with this as well as usage of function modules.

Nazeer

Hi,

First get the string lengthof the variable.

data: lv_string type char4 value ‘ABCD’,

lv_new type i,

lv_new1 type char2.

*lv_new = strlen(lv_string).

CALL FUNCTION ‘STRING_LENGTH’

EXPORTING

string = lv_string

IMPORTING

LENGTH = lv_new


lv_new = lv_new – 2.

lv_new1 = lv_string+lv_new(2).

write lv_new1.

You get the last two characters.

reward if useful..

regards,

nazeer

Verdict

Useful, but no reward. Nazeer narrowly misses the final round by misunderstanding the question.

‘AAAAAAAA BBBB 1 QQQQQQQQ 2’.

i need to take the last letter (2) to do more things b4.

He misinterprets the 2 given as the output to the author’s example input, and instead gives the solution on how to return the last 2 characters.

Nazeer gets plus points for solving his variant of the problem correctly. His code, once cleaned up, makes sense and even compiles! He also provided an alternative solution.

report zfh.

data: lv_string type char4 value 'ABCD',
      lv_new    type i,
      lv_new1   type char2.

*lv_new = strlen( lv_string ).

call function 'STRING_LENGTH'
  exporting
    string = lv_string
  importing
    length = lv_new.

lv_new = lv_new - 2.
lv_new1 = lv_string+lv_new(2).

write lv_new1.

Ramgansean K


Miguel,

One way to do this is ,

◉ find the string length by usinf strlen(strVariableName or String) command.

◉ Find the string lenght-1 posotion of that string.

Regards,

<b>Ramganesan K</b>

Verdict

Would you mind if I just called you Ram? Ram’s algorithm is correct, but he does not specify exactly how to Find the string lenght-1 posotion of that string, which might be important. The ABAP +off(len) syntax might not be familiar to everyone and there might be different methods as well.

Former member #2


use the below code.

data : l_length type i,

l_data(50).

l_data = ‘AAAAAAAA BBBB 1 QQQQQQQQ 2’.

l_length = STRLEN( l_data ) . ” here u will get the length of the field l_data.

by using the length read your variable l_data

and get the last 2 records

Verdict

#2 surprises us with exactly the same misunderstanding of the question Nazeer had. His code is missing the final line of code, which is instead explained, giving us a nice hybrid solution.

Additional entries

from a similar StackOverflow question from 2018:

SAP ABAP Tutorials and Materials, SAP ABAP Learning, SAP ABAP Guides, SAP ABAP Online Exam, SAP ABAP Exam Prep

Note how the code snippets are actually readable without having to copy-paste it somewhere else first. Both solutions produce correct results. Despite its author’s confidence, the second snippet is worse in performance, but it is downvoted and there is a recent comment from Sandra Rossi explaining why it’s slower. Thank you for doing that. Your efforts are not in vain.

Final round


To pick a winner, I will do some actual measurements of the correct approaches.

◉ offset/length
◉ substring
◉ rotate using SHIFT, return first character

The run times will be measured on a short string (guid) and a long string (5000 concatenated guids)

report zlastchar.

class lcl_string_util definition create private.

  public section.

    " feel free to substitute your favorite single character abstraction
    types: t_last_character type c length 1.

    class-methods:
      get_using_substring
        importing str           type string
        returning value(result) type t_last_character.

    class-methods:
      get_using_off_len
        importing str           type string
        returning value(result) type t_last_character.

    class-methods get_using_shift
      importing value(str)    type string
      returning value(result) type t_last_character.

endclass.

class lcl_profiler definition create private.
  public section.

    class-data: guid type string.
    class-data: n type i.

    class-methods: 
      off_len,
      substring,
      shift.

endclass.

""""""""""""""""""""""""""""""""""""
" we will measure a random short string as well as a much longer string

lcl_profiler=>n = 10000.

lcl_profiler=>guid = cl_system_uuid=>create_uuid_c36_static( ).

data(really_long_string) = ``.
do 5000 times.
  really_long_string = really_long_string && cl_system_uuid=>create_uuid_c36_static( ).
enddo.


lcl_profiler=>off_len( ).
lcl_profiler=>substring( ).
lcl_profiler=>shift( ).

""""""""""""""""""""""""""""""""""""

class lcl_string_util implementation.

  method get_using_substring.
    result = substring( off = strlen( str ) - 1 len = 1 val = str ).
  endmethod.

  method get_using_off_len.
    data(index_before_last) = strlen( str ) - 1.
    result = str+index_before_last(1).
  endmethod.

  method get_using_shift.
    shift str right by 1 places circular.
    result = str(1).
  endmethod.

endclass.


class lcl_profiler implementation.

  method off_len.
    do n times.
      lcl_string_util=>get_using_off_len( guid ).
      lcl_string_util=>get_using_off_len( really_long_string ).
    enddo.
  endmethod.

  method substring.
    do n times.
      lcl_string_util=>get_using_substring( guid ).
      lcl_string_util=>get_using_substring( really_long_string ).
    enddo.
  endmethod.

  method shift.
    do n times.
      lcl_string_util=>get_using_shift( guid ).
      lcl_string_util=>get_using_shift( really_long_string ).
    enddo.
  endmethod.

endclass.

And the measurements (in microseconds):

SAP ABAP Tutorials and Materials, SAP ABAP Learning, SAP ABAP Guides, SAP ABAP Online Exam, SAP ABAP Exam Prep

Using offset/length or the substring function seems to be largely equivalent, very slightly favoring offset/length. Which makes it the winner!

But the shift approach really is taking over 30x as long. Still, you might say it doesn’t amount to much… it’s a few miliseconds for 10 000 iterations. Who cares?

Let’s try an even longer string by concatenating 50 000 guids. Now the shift method takes 10 seconds, while the first two approaches still only take about 11 miliseconds.

SAP ABAP Tutorials and Materials, SAP ABAP Learning, SAP ABAP Guides, SAP ABAP Online Exam, SAP ABAP Exam Prep

Perhaps if your application crumbles when faced with large volumes of data, you don’t have to do anything crazy to fix it. Maybe you’re just doing a basic thing incorrectly too many times.

And now that I have this out of my system, I can go back to delivering you the intelligent enterprise. Stay tuned.

Edit: if you’re a new abaper, make sure not to take the suggestions from the comments section too seriously.

◉ It’s true that the database can do a lot of heavy lifting for you, but code pushdown is not to be used for trivial things.

◉ Even though you can use sql directly in abap, make sure to encapsulate database access or your code will be difficult to test

Source: sap.com

No comments:

Post a Comment