Skip to end of metadata
Go to start of metadata

Author: Alexey Arseniev
Submitted: 18.12.2015

Other code samples from me:

Why

There is a lot of use case when you need to do a conversion of the number from one base to another. And you need the implementation for ABAP

The most trivial you need easy conversion method of numbers written in different formats, as:

  • Convert binary number to decimal or decimal to binary: 101010101111010111010 <=> 1400506
  • Convert hexadecimal (hex) to decimal or decimal to hexadecimal : 895678 <=>  DAABE
  • Or binary to hexadecimal ;)

Another reason, which is maybe not so obvious but still important, is to minimize data length used by the number if you plan to transmit numbers in textual form. The use case may be: you need an ID, which is a decimal number, and it shall be used in a string with limited length (as URL). Here conversion of the decimal to a higher base may result in significantly reducing of text ID length (depends on base):

Decimal (base 10) number

62 base number

Compression Ratio

999999999999999

4zXyLE1Gv

60%

How

When doing conversion what is matter?

  • Source base (normally decimal)
  • Target base (hex = 16, binary = 2, octal = 8, base64 = 64)
  • Alphabet for base conversion. Alphabet used to control which characters are used in target string for representing the number. Standard binary alphabet will be ‘01’, for HEX ‘0123456789ABCDEF’ etc, but you can also use any alternative alphabet. Most important that alphabet used for encoding is same as for decoding, otherwise you will not get a symmetric conversion. The class provided include built-in alphabet that can be used when no other alphabet is provided and support conversion of numbers stored in up to 92 bases (printable characters).

Usage example

Usage of the code is straightforward. See examples below for assistance:

Error rendering macro 'code': Invalid value specified for parameter 'com.atlassian.confluence.ext.code.render.InvalidValueException'
DATA: lv_output TYPE string.
TRY .
    lv_output = /ui2/cl_number=>base_converter( number = 999999999999999 ).
    WRITE: / `Decimal 999999999999999 in base 62 is`, lv_output.
  CATCH cx_sy_move_cast_error.
    WRITE: / `Conversion error`.
ENDTRY.
TRY .
    lv_output = /ui2/cl_number=>base_converter( number = '101010101111010111010' from = 2 to = 10 ).
    WRITE: / `Binary 101010101111010111010 as decimal is`, lv_output.
  CATCH cx_sy_move_cast_error.
    WRITE: / `Conversion error`.
ENDTRY.
TRY .
    lv_output = /ui2/cl_number=>base_converter( number = '101010101111010111010' from = 2 to = 8 ).
    WRITE: / `Binary 101010101111010111010 in base 8 is`, lv_output.
  CATCH cx_sy_move_cast_error.
    WRITE: / `Conversion error`.
ENDTRY.
TRY .
    lv_output = /ui2/cl_number=>base_converter( number = 895678 to = 16 ).
    WRITE: / `Decimal 895678 as hexadecimal is`, lv_output.
  CATCH cx_sy_move_cast_error.
    WRITE: / `Conversion error`.
ENDTRY.

Using for converting to base64

Normally, for converting from decimal to base64 or vice versa you do not need an extra class, but can use built-in functions as SSFC_BASE64_ENCODE for doing the job – it is faster and available everywhere. There is helper method BASE64_CONVERTER include which you may use for convenience.

But if for some reason you cannot use it, it also works with the BASE_CONVERTER method, but do not forget to provide base64 alphabet as input (it is different from default). See examples below for your assistance:

Error rendering macro 'code': Invalid value specified for parameter 'com.atlassian.confluence.ext.code.render.InvalidValueException'
DATA: lv_output TYPE string.
TRY .
    lv_output = /ui2/cl_number=>base_converter( number = 9999999 to = 64 alphabet = /ui2/cl_number=>mc_alphabet_base64 ).
    WRITE: / `Decimal 9999999 encoded with base64 is`, lv_output.
    lv_output = /ui2/cl_number=>base64_converter( number = 9999999 ).
    WRITE: / `Decimal 9999999 encoded with base64 in standard/faster way is`, lv_output.
  CATCH cx_sy_move_cast_error.
    WRITE: / `Conversion error`.
ENDTRY.

Alphabets

AlphabetCharactersDescription
MC_ALPHABET0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-_.~!*{}'();:@&=+$,/?#[]%<>"§|\^Default alphabet used for encoding if no alternative alphabet provided. Supports standard base conversion of binary, octal, decimal, hex and base62. Not compatible with the base64 alphabet.
MC_ALPHABET_ASCII85 0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ.-:+=^!/*?&<>()[]{}@%$# Longest standard alphabet that can be used for encoding. Details can be found here:  https://www.wikipedia.org/wiki/Ascii85
MC_ALPHABET_BASE64 ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/ Base64 compatible alphabet. Details:  https://www.wikipedia.org/wiki/Base64
MC_ALPHABET_BASE58 123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz

Human-friendly alphabet without ambiguous characters (to avoid mistyping). Details: https://www.wikipedia.org/wiki/Base58

MC_ALPHABET_BASE32 ABCDEFGHIJKLMNOPQRSTUVWXYZ234567

One of base32 alphabets optimized for human readability.

Details: https://www.wikipedia.org/wiki/Base32

Supported SAP_BASIS releases

The class contains no special language constructions or external dependencies (not sure about FM SSFC_BASE64_ENCODE), so I think you can use it as a copy from SAP_BASIS 6.40. If you want to use it directly – see below.

The most actual implementation, with unit tests etc. can be found in class /UI2/CL_NUMBER delivered within SAP UI Add-on V2 SP02 and higher (SAP_UI for 7.5X, SAP_BASIS for 7.6X). But it is recommended to use your own renamed local copy, to avoid any inconsistencies, if logic or default alphabet would be changed in the future.

The /UI2/CL_NUMBER code

Copy/Paste snippet for local class:

Number base conversion using /UI2/CL_NUMBER in ABAP
*----------------------------------------------------------------------*
*       CLASS /UI2/CL_NUMBER DEFINITION
*----------------------------------------------------------------------*
*
*----------------------------------------------------------------------*
CLASS /ui2/cl_number DEFINITION.
  PUBLIC SECTION.
    CONSTANTS mc_alphabet TYPE string VALUE `0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-_.~!*{}'();:@&=+$,/?#[]%<>"§|\^`. "#EC NOTEXT
    " https://www.wikipedia.org/wiki/Ascii85
    CONSTANTS mc_alphabet_ascii85 TYPE string VALUE `0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ.-:+=^!/*?&<>()[]{}@%$#`. "#EC NOTEXT
    " https://www.wikipedia.org/wiki/Base64
    CONSTANTS mc_alphabet_base64 TYPE string VALUE `ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/`. "#EC NOTEXT
    " https://www.wikipedia.org/wiki/Base58
    CONSTANTS mc_alphabet_base58 TYPE string VALUE `123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz`. "#EC NOTEXT
    " https://www.wikipedia.org/wiki/Base32
    CONSTANTS mc_alphabet_base32 TYPE string VALUE `ABCDEFGHIJKLMNOPQRSTUVWXYZ234567`. "#EC NOTEXT
    CLASS-METHODS base64_converter
      IMPORTING
        number TYPE any
      RETURNING
        value(rv_value) TYPE string .
    CLASS-METHODS base_converter
      IMPORTING
        number TYPE any
        from TYPE i DEFAULT 10
        to TYPE i DEFAULT 62
        alphabet TYPE csequence OPTIONAL
      RETURNING
        value(rv_value) TYPE string
      RAISING
        cx_sy_move_cast_error .
ENDCLASS.                    "/UI2/CL_NUMBER DEFINITION
*----------------------------------------------------------------------*
*       CLASS /UI2/CL_NUMBER IMPLEMENTATION
*----------------------------------------------------------------------*
*
*----------------------------------------------------------------------*
CLASS /ui2/cl_number IMPLEMENTATION.
  METHOD base_converter.
    DATA: lv_decimal   TYPE p,
          lv_alphabet  TYPE string,
          lv_number    TYPE string,
          lv_length    TYPE i,
          lv_last      TYPE i,
          lv_index     TYPE i.
    IF alphabet IS INITIAL.
      lv_alphabet = mc_alphabet.
    ELSE.
      lv_alphabet = alphabet.
    ENDIF.
    IF from GT strlen( lv_alphabet ) OR to LT 2.
      RAISE EXCEPTION TYPE cx_sy_move_cast_error.
    ENDIF.
    IF from NE 10.
      MOVE number TO lv_number.
      CONDENSE lv_number.
      lv_length = strlen( lv_number ).
      lv_last = lv_length - 1.
      WHILE lv_last GE 0.
        FIND FIRST OCCURRENCE OF lv_number+lv_last(1) IN lv_alphabet RESPECTING CASE MATCH OFFSET lv_index.
        IF sy-subrc NE 0.
          RAISE EXCEPTION TYPE cx_sy_move_cast_error.
        ENDIF.
        lv_decimal = lv_decimal + lv_index * ( from ** ( lv_length - lv_last - 1 ) ).
        lv_last = lv_last - 1.
      ENDWHILE.
    ELSE.
      MOVE number TO lv_decimal.
    ENDIF.
    IF to NE 10.
      WHILE lv_decimal NE 0.
        lv_index = lv_decimal MOD to.
        CONCATENATE lv_alphabet+lv_index(1) rv_value INTO rv_value.
        lv_decimal = lv_decimal DIV to.
      ENDWHILE.
      IF rv_value IS INITIAL.
        rv_value = '0'.
      ENDIF.
    ELSE.
      rv_value = lv_decimal.
      CONDENSE rv_value.
    ENDIF.
  ENDMETHOD.                    "base_converter
  METHOD base64_converter.
    DATA: lv_xstring  TYPE xstring.
    lv_xstring = number.
    CALL FUNCTION 'SSFC_BASE64_ENCODE'
      EXPORTING
        bindata = lv_xstring
      IMPORTING
        b64data = rv_value
      EXCEPTIONS
        OTHERS  = 1.
    IF sy-subrc IS NOT INITIAL.
      CLEAR rv_value.
    ENDIF.
  ENDMETHOD.                    "base64_converter
ENDCLASS.                    "/UI2/CL_NUMBER IMPLEMENTATION