点击蓝字 关注我们

前言

ABAP语言作为一个相对封闭的语言,很难在网上找到一些经典算法的源代码.

尝试自行通过ABAP语句去实现这些经典算法是一个办法,有利于我们理解这些算法,同时可以更深入的掌握ABAP语言.

但是ABAP语言本身设计初衷是为了解决企业信息化的问题.ABAP语言更贴切关系数据处理比如我们可以通过变量或工作区的字段对应一个字段,工作区对应一条记录, 通过内表对应一个物理表,内表操作可以很方便与物理表交互.

新的ABAP语法甚至支持用SELELCT 语句操作内表. 可以用内表与物理表关联等.

同时ABAP语句对数字计算的支持又不太够. (如图一),ABAP支持的数字运算只包括加,减,乘,除,整除,取余,乘方.

一些常用的数学计算如开方,对数计算( LOG )等不支持.

这样就导致一些复杂的算法可能很难通过ABAP语句实现.

说了这么多理由都抵不过这两字:偷懒

为了大家一起偷懒

本文介绍一下怎么使用ABAP调用JAVASCRIPT语句,文中示例实现了一个经典的字符匹配度算法-levenshteinDistance

文中简称 JAVASCRIPT=JS

图一

调用方式

基本类 CL_JAVA_SCRIPT

CL_JAVA_SCRIPT是ABAP对JS调用的基本类.具体用法比较简单,如下图的示例程序(该程序使用JS验证邮箱合法性). 示例程序详见文末

01

定义变量

02

创建对象

03

赋值JS代码

变量要作为代码内容的一部分赋值到JS代码中

调用方法,编译并执行JS代码,并获取返回值

弊端

上述方式,可以非常简单的实现对JS代码的调用. 

但是因为变量是通过JS代码的一部分传入的. 所以如果需要大量调用(验证email邮箱)时, 每次都需要编译后再执行这个JS代码. 数据量过大时,重复编译将消耗过多的性能.

改进方法

CL_JAVA_SCRIPT本身附带了单独的编译,执行方法.

  • COMPILE 编译

  • EXECUTE 执行

  • DESTROY 释放

  • EVALUATE 编译,执行,释放JS

一个可能的性能改进方式是建立一个ABAP与JAVASCIPRT的通信机制,通过数据库表传递是目前想到的一种方式. 请精通JS的读者也帮忙考虑一下其它的通讯方式. 

(比如ODATA,RFC,HTTP,WEBSERVICE) 等.

后续有机会将尝试一下通过这些不同的方式交互数据

字符相似度的算法

算法解释详见

计算字符串相似度算法——Levenshtein - 路在脚下 - ITeye博客

https://www.iteye.com/blog/wdhdmx-1343856

多谢网友ABAP-慎の久-深圳在公众号消息中提供字符匹配度话题及上述链接

字符相似度算法的JS实现,该实现方式来自网络搜索.

JS源代码详见文末

字符相似度封装类

封装到SAP类中的JS调用

( ZCL_REP_COMM_CALL_JAVASCRIPT=>LEVENSHTEIN_DISTANCE ),源代码详见文末

01

传递变量 

方法参数->JS

02

返回值的加工处理

LEVENSHTEIN_DISTANCE 算法计算了两个字符串的差异值. 通过这个公式

匹配度= (1 - 差异值/MAXLEN(字符A,字符B) )

可以计算出匹配度,封装类返回值*100. 单位 %

ABAP调用JS示例代码

示例程序

*&---------------------------------------------------------------------*
REPORT zts_abap_call_javascript.


DATA: g_js         TYPE REF TO cl_java_script,
      g_javascript TYPE string,
      g_return     TYPE string.


PARAMETERS: p_email TYPE char20.


START-OF-SELECTION.
*定义对象
  g_js = cl_java_script=>create( ).


*一个简单的验证email的javascript功能
  CONCATENATE
  'var e = "' p_email '";' INTO g_javascript.
  CONCATENATE g_javascript
  'function validEmail(e) {'
  ' var filter = /^\s*[\w\-\+_]+(\.[\w\-\+_]+)*\@[\w\-\+_]+\.[\w\-\+_]+(\.[\w\-\+_]+)*\s*$/;'
  ' return String(e).search (filter) != -1;'
  ' }'
  'validEmail(e);'
  INTO g_javascript SEPARATED BY cl_abap_char_utilities=>cr_lf.


*获取javascript函数的返回值
  g_return = g_js->evaluate( g_javascript ).


*输出调用结果
  IF g_js->last_condition_code IS NOT INITIAL.
    WRITE: /'Error : ', g_js->last_error_message.
  ELSE.
    WRITE: /'Email ID ', p_email NO-GAP, ' is Valid : ', g_return.
  ENDIF.

字符匹配度源码

levenshteinDistance的JS 源代码(该源代码来自网络,版权归INTERNET. 

function levenshteinDistance(s,t){
    if(s.length>t.length){
        vartemp=s;
        s=t;
        t=temp;
        deletetemp;
    }
    varn=s.length;
    varm=t.length;
    if(m==0){
        returnn;
    }
    else if(n==0){
        returnm;
    }
    varv0=[];
    for(var i=0;i<=m;i++){
        v0[i]=i;
    }
    var v1=new Array(n+1);
    varcost=0;
    for(var i=1;i<=n;i++){
        if(i>1){
            v0=v1.slice(0);
        }
        v1[0]=i;
        for(var j=1;j<=m;j++){
            if(s[i-1].toLowerCase()==t[j-1].toLowerCase()){
                cost=0;
            }
            else{
                cost=1;
            }
            v1[j]=Math.min.call(null,v1[j-1]+1,v0[j]+1,v0[j-1]+cost);
        }
    }
    returnv1.pop();
}


//Test
levenshteinDistance("gUMBO","GAMBOL");//output 2

字符配置度类

LEVENSHTEIN_DISTANCE 调用JS的类实现

  METHOD levenshtein_distance.
    DATA: lc_js         TYPE REF TO cl_java_script,
          lv_javascript TYPE string,
          lv_return     TYPE string.


* Create JavaScript
    lc_js = cl_java_script=>create( ).


* Build JavaScript Code
*赋值变量
    DATA: lv_line TYPE string.
    CLEAR lv_line.
    CONCATENATE  'var stra = "' iv_stra '";' INTO lv_line.
    lv_javascript = lv_line.


    CLEAR lv_line.
    CONCATENATE   'var strb = "' iv_strb '";' INTO lv_line.
    CONCATENATE lv_javascript lv_line INTO lv_javascript SEPARATED BY cl_abap_char_utilities=>cr_lf.


*添加函数
    CONCATENATE lv_javascript
  ' function levenshteinDistance(s,t){                                        '
  '     if(s.length>t.length){                                                '
  '         var temp=s;                                                       '
  '         s=t;                                                              '
  '         t=temp;                                                           '
  '         delete temp;                                                      '
  '     }                                                                     '
  '     var n=s.length;                                                       '
  '     var m=t.length;                                                       '
  '     if(m==0){                                                             '
  '         return n;                                                         '
  '     }                                                                     '
  '     else if(n==0){                                                        '
  '         return m;                                                         '
  '     }                                                                     '
  '     var v0=[];                                                            '
  '     for(var i=0;i<=m;i++){                                                '
  '         v0[i]=i;                                                          '
  '     }                                                                     '
  '     var v1=new Array(n+1);                                                '
  '     var cost=0;                                                           '
  '     for(var i=1;i<=n;i++){                                                '
  '         if(i>1){                                                          '
  '             v0=v1.slice(0);                                               '
  '         }                                                                 '
  '         v1[0]=i;                                                          '
  '         for(var j=1;j<=m;j++){                                            '
  '             if(s[i-1].toLowerCase()==t[j-1].toLowerCase()){               '
  '                 cost=0;                                                   '
  '             }                                                             '
  '             else{                                                         '
  '                 cost=1;                                                   '
  '             }                                                             '
  '             v1[j]=Math.min.call(null,v1[j-1]+1,v0[j]+1,v0[j-1]+cost);     '
  '         }                                                                 '
  '     }                                                                     '
  '     return v1.pop();                                                      '
  ' }                                                                         '
      INTO lv_javascript SEPARATED BY cl_abap_char_utilities=>cr_lf.


*添加函数调用
    CONCATENATE lv_javascript
     ' levenshteinDistance(stra,strb);//output 2 '
           INTO lv_javascript SEPARATED BY cl_abap_char_utilities=>cr_lf.


*Get the return value
*获取返回值:该返回值是Levenshtein 距离的返回值.
    lv_return = lc_js->evaluate( lv_javascript ).
*匹配度= 1 - Levenshtein 距离 / 两个字符串较长的长度
    DATA: lv_strlen TYPE i.
    IF strlen( iv_stra ) > strlen( iv_strb ).
      lv_strlen = strlen( iv_stra ).
    ELSE.
      lv_strlen = strlen( iv_strb ).
    ENDIF.
    ev_match = ( 1 - lv_return / lv_strlen ) * 100.
  ENDMETHOD.

总结

通过ABAP调用JS可以简单方便的通过ABAP实现一些经典算法(前提是网络上可以找到这些经典算法的JS实现).本文示例给出了LEVENSHTEIN_DISTANCE (字符匹配度算法). 希望通过本文给出的方式实现了其它经典算法的朋友,可以在公主号微信群中分享出来.

ABAPER从此抱上JS的大腿,过上没羞没臊的幸福生活.

THE

END

约定

如果你对这篇文章感兴趣,请帮忙点赞,在看,分享.       

    (如果你真的喜欢这篇文章,请记得回来打个赏,作为支持我继续下去的动力,这是一个正反馈过程. 越多的人打赏,作者越有动力分享,读者就能享受更多的福利.毕竟打赏的金额富不了我,穷不了你,却能支持这个公众号长久发文.)

公众号 : syjf1976_abap

          ABAP开发技巧

微信号 : 392077

公众号主群加入受限, 请扫码加入副群后,向管理员申请加入主群

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐