原创 无峰 [ ABAP 技巧与实战 ](javascript:void\(0\);)
**点击蓝字** 关注我们
一
前言
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();}
//TestlevenshteinDistance("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.十
总结
...