Introducción
No siempre tenemos que preocuparnos de la codificación de caracteres de los ficheros que abrimos y cerramos en R/3, pero en ocasiones sí. Por ejemplo, cuando destinados a un proyecto en Japón debemos hacer una carga de clientes con nombres etruscos.
Si realmente no estás familiarizado/a con el concepto de juegos de caracteres, es muy importante superar el mito extendidísimo de que un caracter de texto ocupa siempre un byte. Eso es cierto para la mayoría de textos en inglés que no usan caracteres extraños, o cuando utilizamos textos de windows y nuestro SAPGUI está enterado de por donde se mueve. Pero no siempre ocurre así.
Podría extenderme sobre las diversas variaciones de juegos de caracteres, sistemas de codificación, etc… pero no lo voy a hacer porque ya hay un estupendo artículo que explica en que consisten y, esencial, porque llegaron a ser como son: Lo Absolutamente Mínimo que cada Desarrollador de Software, Absoluta y Positivamente, Debe Saber sobre Unicode y Juegos de Caracteres. Este texto, muy clarificador, unido a este FAQ sobre UTF, debería ser bastante para entender lo esencial sobre este asunto.
El código que adjunto es una demostración de cómo se pueden utilizar objetos ABAP para convertir textos de unos sistemas de codificación a en otros. Para facilitar las pruebas, hago uso de la interesante función SCMS_STRING_TO_XSTRING para transformar el texto del parámetro de entrada del report en xstring. ¿Por qué?
Obviamente no podemos trabajar con strings puros, ya que de ese modo su contenido real, sus bytes, permanecen opacos a nuestra vista durante su tratamiento. Por eso se hace absolutamente necesario el uso de xstrings, con lo que a la hora de cargar y grabar ficheros codificados de modo extraño lo haremos en modo binario.
Es importante señalar que ABAP no utiliza los diversos nombres y alias de los distintos juegos de caracteres para realizar las conversiones, ya que utiliza un código numérico interno para definirlos. Existe una función que traduce, más bien intenta, los nombres estándar a estos códigos internos. Pero funciona tan horrorosamente mal y es tan poco práctica que ni la menciono. Es mucho mejor mirar directamente el contenido de la tabla TCP00, cruzar los dedos y deducir, a base de pruebas (este mismo programa puede ayudar) cual es el código numérico que necesitamos. Digo lo de las pruebas porque las descripciones son espantosas y muy poco clarificadoras.
Como curiosidad: el programa RSCPINST muestra los juegos de caracteres utilizados en SAPGUI, servidor y base de datos. Quizás sirva de ayuda.
El código
REPORT zzcharsetsycodepages NO STANDARD PAGE HEADING. "As seen on http://cranf.com DATA windows1252 TYPE xstring. "xcadena en windows1252 DATA utf8 TYPE xstring. "xcadena en UTF-8 DATA utf16 TYPE xstring. "xcadena en UTF-16 DATA conversionutf8 TYPE REF TO cl_abap_conv_x2x_ce. "instancia de la conversión DATA conversionutf16 TYPE REF TO cl_abap_conv_x2x_ce. "instancia de la conversión DATA longitud TYPE i. "lo necesitamos, queramos o no "parámetro de entrada PARAMETERS cadena TYPE string LOWER CASE DEFAULT 'España Cañí y Olé'. "********************************************************************** * _ _ __ _ _ * ___| |_ _ __(_)_ __ __ _\ \__ _____| |_ _ __(_)_ __ __ _ */ __| __| '__| | '_ \ / _` |\ \ \/ / __| __| '__| | '_ \ / _` | *\__ \ |_| | | | | | | (_| |/ /> <\__ \ |_| | | | | | | (_| | *|___/\__|_| |_|_| |_|\__, |_//_/\_\___/\__|_| |_|_| |_|\__, | * |___/ |___/ "en un primer paso tiramos de la función de conversión de string en xstring, "pasándole el código interno de charset ABAP (están en la tabla TCP00) CALL FUNCTION 'SCMS_STRING_TO_XSTRING' EXPORTING text = cadena encoding = '1160' "windows1252, véase tabla TCP00 para deducir número IMPORTING buffer = windows1252 EXCEPTIONS failed = 1 OTHERS = 2. "esta función nos puede bastar para conversión de un string en la cadena hexadecimal "con el charset que nos dé la gana. estupenda, ¿verdad? "********************************************************************** * _ _ _ * ___ |__ __ _ _ _____ ___ |_ ___ ___ _ ___ ____ _ _____(_)___ _ __ * / __|'_ \/ _` | '__|__| _ \__| / __| _ \ '_ \\ / /_ \ '__|__| | _ \ '_ \ *| (__ | | |(_| | | \__ \ __/|_ | (__ (_) || | |V / __/ | \__ \ |(_) || | | * \___|| |_|__,_|_| |___/___|__| \___|___/_| |_|_/\___|_| |___/_|___/_| |_| * "pero ahora vamos a pasar de un xstring a otro xstring con distinta codificación "instanciamos primero el objeto conversor TRY. CALL METHOD cl_abap_conv_x2x_ce=>create EXPORTING in_encoding = '1160' "windows1252 ignore_cerr = abap_false out_encoding = '4110' "código utf-8, véase tabla TCP00 input = windows1252 RECEIVING conv = conversionutf8. "es la instancia de un objeto, ojo! CATCH cx_parameter_invalid_type . CATCH cx_parameter_invalid_range . CATCH cx_sy_codepage_converter_init . ENDTRY. "convertimos occidental a UTF-8 TRY. CALL METHOD conversionutf8->convert_c IMPORTING len = longitud. ENDTRY. "y obtenemos el valor UTF8 como xstring CALL METHOD conversionutf8->get_out_buffer RECEIVING buffer = utf8. "********************************************************************** "para rizar el rizo, pasamos de UTF8 a UTF16 little endian TRY. CALL METHOD cl_abap_conv_x2x_ce=>create EXPORTING in_encoding = '4110' "código utf-8, véase tabla TCP00 ignore_cerr = abap_false out_encoding = '4103' "utf-16 little endian (4102 sería big endian) out_endian = 'L' "indica opcionalmente big endian / little endian input = utf8 RECEIVING conv = conversionutf16. "instancia del objeto CATCH cx_parameter_invalid_type . CATCH cx_parameter_invalid_range . CATCH cx_sy_codepage_converter_init . ENDTRY. "hacemos la conversión de UTF8 a UTF16 TRY. CALL METHOD conversionutf16->convert_c IMPORTING len = longitud. ENDTRY. "obtenemos finalmente el valor UTF16 como xstring CALL METHOD conversionutf16->get_out_buffer RECEIVING buffer = utf16. "********************************************************************** "y aquí los resultados WRITE: / 'String :', cadena. WRITE: / 'windows1252 :', windows1252. WRITE: / 'UTF-8 :', utf8. WRITE: / 'UTF-16 :', utf16.
Tras ejecutarse el programa con el parámetro por defecto, veremos un resultado tal que así:
String : España Cañí y Olé windows1252 : 45737061F161204361F1ED2079204F6CE9 UTF-8 : 45737061C3B161204361C3B1C3AD2079204F6CC3A9 UTF-16 : 4500730070006100F1006100200043006100F100ED002000790020004F006C00E900