ABAP 程序中使用正则表达式验证邮箱格式是否正确

2023年 8月 22日 115.3k 0

问题来源

在开发过程中,经常会遇到一些数据校验的问题,比如我们必须从屏幕字段、Web Dynpro 输入字段或上传文件的文本中验证电子邮件地址。验证可确保您具有有效的电子邮件格式以进行进一步处理,例如发送通知或将其存储在数据库中。

这次在实际业务中,用户比较看重邮件的正确性,如果是 SAP 的数据元素 AD_SMTPADR 就是带标准的校验功能的。

image.png

如果我们输入不带 @ 符号的邮箱,就会在标准错误中得到如下的提示:

消息号 XS138:电子邮箱地址 XXXsam.com 无效

image.png

通过 DEBUG 可以看到这段程序:

IF ADDRESS_UNSTRUCT-ADDRESS NP '*@*' AND COMPLETE_ADDRESS = SX_TRUE.  
    MESSAGE E138 WITH ADDRESS_UNSTRUCT-ADDRESS ADDRESS_UNSTRUCT-TYPE  
                      TEXT-028 TEXT-039  
    RAISING ERROR_ADDRESS.  
ENDIF.

解读:从上面的代码可以看出有一个条件是查看 ADDRESS_UNSTRUCT-ADDRESS NP '*@*',它检查 ADDRESS_UNSTRUCT-ADDRESS 这个邮箱变量的值是否包含字符串 @。 如果包含就报出 E138 这个错误。

这段校验会有缺陷,当我们输入一个不带域名的邮箱时,不会得到系统的错误:

image.png

正则表达式

关于电子邮箱的正则表达式有很多,具体可以看一下这个网站提供了一些常见的正则库:RegExLib。

这里使用一种常见的电子邮箱的正则表达式:w+(.w+)*@(w+.)+(w{2,4})

  • w 表示匹配任意字母、数字、下划线
  • + 表示匹配前面的元素至少出现一次
  • * 表示匹配前面的元素任意次

接下来解释一下这个正则模式:

  • w+(.w+): @ 前面的第一部分将接受任何字母、数字字符或带或不带 (.) 点的字符。这部分w+ 匹配多个字母或数字。 (.w+) 验证是否有一个点,且 . 后面必须跟一个字符。
  • (w+.):@ 后面的部分允许灵活地使用任何名称(后面带有 (.) 点)。这一部分 (w+.) 确保结束部分之前至少有一个域。如果有多个,它将检查域的每个部分后面的 (.) 点。
  • (w{2,4}):最后一部分确保电子邮件在最后一个点之后至少有 2 个字符,最多 4 个字符。

此外,你可以在 regerxr.com 中找到每种模式的解释

问题解决

SAP 提供了一个非常有用的API,让您可以使用正则表达式验证电子邮件地址。使用 ABAP RegEx 实用程序类 CL_ABAP_REGEXCL_ABAP_MATCHER 验证电子邮件。

验证电子邮件的步骤如下:

  • 首先,编写一个与电子邮件地址匹配的正则表达式。
  • 然后,创建一个类的实例 cl_abap_regex ,该实例具有名为 regex 对象的电子邮件地址模式。
  • 最后,从上面的 regex 对象创建一个 matcher 对象,它是 class 的实例 cl_abap_matcher ,并调用 匹配对象的 match() 方法。如果方法的返回值 match() 不为空,则电子邮件地址有效。否则无效。
REPORT  zvalidateemail.

DATA: go_regex   TYPE REF TO cl_abap_regex,
      go_matcher TYPE REF TO cl_abap_matcher,
      go_match   TYPE c LENGTH 1,
      gv_msg     TYPE string.

PARAMETERS: p_email TYPE ad_smtpadr.

START-OF-SELECTION.

  CREATE OBJECT go_regex
    EXPORTING
      pattern     = 'w+(.w+)*@(w+.)+(w{2,4})'
      ignore_case = abap_true.

  go_matcher = go_regex->create_matcher( text = p_email ).

  IF go_matcher->match( ) IS INITIAL.
    gv_msg = 'Email address is invalid'.
  ELSE.
    gv_msg = 'Email address is valid'.
  ENDIF.

  MESSAGE gv_msg TYPE 'I'.

类实现

CLASS lcl_mail DEFINITION.
  PUBLIC SECTION.
    METHODS validate_email_id
      IMPORTING
        iv_email TYPE ad_smtpadr
      RETURNING
        VALUE(RESULT) TYPE flag .
ENDCLASS.                    "lcl_mail DEFINITION
*
START-OF-SELECTION.
  DATA: lo_mail TYPE REF TO lcl_mail.
  CREATE OBJECT lo_mail.
  IF lo_mail->validate_email_id( 'szdfd@' ) IS INITIAL.
    WRITE: 'Invalid Email'.
  ELSE.
    WRITE: 'Valid'.
  ENDIF.
*
CLASS lcl_mail IMPLEMENTATION.
  METHOD validate_email_id.
 
* Local Data
    DATA:  REGEX   TYPE REF TO cl_abap_regex,       " Regex Object
           matcher TYPE REF TO cl_abap_matcher,     " Matcher Object
           MATCH   TYPE c LENGTH 1,                 " Match ?
           mail_to_check(100).                      " Email ID to check
 
    mail_to_check = iv_email.
 
    RESULT = abap_true.  "Email is valid
 
* Instntiate Regex
    CREATE OBJECT REGEX
      EXPORTING
        pattern     = 'w+(.w+)*@(w+.)+(w{2,4})'
        ignore_case = abap_true.
 
* Create the Matcher
    matcher = regex->create_matcher( text = mail_to_check ).
 
* Match not found, invalid
    IF matcher->MATCH( ) IS INITIAL.
      RESULT = abap_false.  "Email not valid
      EXIT.
    ENDIF.
 
  ENDMETHOD.                    "validate_email_id
ENDCLASS.                    "lcl_mail IMPLEMENTATION

官方实现

程序通过将输入的电子邮件地址与正则表达式进行比较,检查其形式上的正确性。

  • 第一个正则表达式检查不含特殊字符的标准电子邮件地址,而第二个正则表达式则根据 RFC 822 执行更宽松的语法检查。
  • 即使是使用相对简单的正则表达式作为示例的第二种检查,也并非总是与 RFC 822 规定的所有电子邮件地址兼容。
  • DEMO_VALIDATE_RFC_822_ADDRESS 程序使用的正则表达式来自互联网,旨在识别 RFC 822 允许的所有电子邮件地址。这里的正则表达式最初是为 Perl 编写的,有 6000 多个字符。因此,该程序是如何在 ABAP 中不使用正则表达式的一个示例。
REPORT demo_matches.  
  
CLASS demo DEFINITION.  
  PUBLIC SECTION.  
    CLASS-METHODS main.  
ENDCLASS.  
  
CLASS demo IMPLEMENTATION.  
  METHOD main.  
    DATA email TYPE string VALUE `abc.def@ghi.jkl`.  
    cl_demo_input=>request( CHANGING field = email ).  
    IF matches( val   = email  
                regex = `w+(.w+)*@(w+.)+(([a-z]|[A-Z]){2,4})` )  
                ##REGEX_POSIX.  
      cl_demo_output=>display( 'Format OK' ).  
    ELSEIF matches(  
             val  = email  
             pcre = `[[:alnum:],!#$%&'*+/=?^_``{|}~-]+`      &  
                    `(.[[:alnum:],!#$%&'*+/=?^_``{|}~-]+)*` &  
                    `@[[:alnum:]-]+(.[[:alnum:]-]+)*`              &  
                    `.([[:alpha:]]{2,})` ).  
      cl_demo_output=>display( 'Syntax OK but unusual' ).  
    ELSE.  
      cl_demo_output=>display( 'Wrong format!' ).  
    ENDIF.  
  ENDMETHOD.  
ENDCLASS.  
  
START-OF-SELECTION.  
  demo=>main( ).

使用方式

DATA: go_regex   TYPE REF TO cl_abap_regex,
        go_matcher TYPE REF TO cl_abap_matcher,
        go_match   TYPE c LENGTH 1.

  CREATE OBJECT go_regex
    EXPORTING
      pattern     = '([a-zA-Z0-9_-.]+)@(([[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}.)|(([a-zA-Z0-9-]+.)+))([a-zA-Z]{2,4}|[0-9]{1,3})(]?)'
      ignore_case = abap_true.

  IF gv_smtp_addr IS NOT INITIAL.

    go_matcher = go_regex->create_matcher( text = gv_smtp_addr ).

    IF go_matcher->match( ) IS INITIAL.

      CLEAR:gv_msg.
      gv_msg = |Email address is invalid|.
      MESSAGE s001(00) WITH gv_msg DISPLAY LIKE 'E'.

      p_error = 'X'.
      RETURN.
    ENDIF.
  ENDIF.

  IF gv_appli_email IS NOT INITIAL.

    go_matcher = go_regex->create_matcher( text = gv_appli_email ).

    IF go_matcher->match( ) IS INITIAL.

      CLEAR:gv_msg.
      gv_msg = |Vendor Applicant Email address is invalid|.
      MESSAGE s001(00) WITH gv_msg DISPLAY LIKE 'E'.

      p_error = 'X'.
      RETURN.
    ENDIF.

  ENDIF.

相关文章

JavaScript2024新功能:Object.groupBy、正则表达式v标志
PHP trim 函数对多字节字符的使用和限制
新函数 json_validate() 、randomizer 类扩展…20 个PHP 8.3 新特性全面解析
使用HTMX为WordPress增效:如何在不使用复杂框架的情况下增强平台功能
为React 19做准备:WordPress 6.6用户指南
如何删除WordPress中的所有评论

发布评论