内容


在 DB2 for Linux, UNIX, and Windows 9.7 上使用正则表达式和模式匹配的 Java 解决方案

Comments

DB2 for Linux, UNIX, and Windows 9.7 和正则表达式

在编程中,正则表达式是用一种形式语言编写的,也称为 regexregexp。它是一种形式模式,一个特定程序使用名为模式匹配 的识别流程在文本或字符串中进行查找。

您可能想使用模式匹配和正则表达式来执行以下基本功能:

  • 查看给定的序列是否看起来像给定的模式
  • 如果在序列中具有特定模式,则使用备用子序列替换子序列
  • 在给定输入序列中匹配子序列的特定发生事件
  • 在给定输入序列中匹配子序列的特定发生事件和位置

DB2 for Linux, UNIX, and Windows 本身不支持使用正则表达式函数。如果您遇到一个需要使用正则表达式函数的实例,则您将很可能要创建用户定义的函数来处理您的要求。

本文向您展示了如何编写您自己的 Java 用户定义函数,以便获得 java.util.regex 包所带来的优势,它提供了关于模式匹配的原子特征。该包提供了一个引擎,可以通过解释模式对字符序列执行操作,即模式成为正则表达式的编译表达式。Java 模式与 Unicode 技术标准 #18:Unicode 正则表达式指南 的第 1 级一致,外加 RL2.1 规范相等性。

本文中所讨论的解决方案不支持序列排序、扩展字形集群或调整字形集群。

本文包括以下部分:

  • Java regex 函数,提出了 Java 函数的规范。
  • 匹配模式,描述了可以通过函数的参数 MODE 指定的模式匹配的不同类型。
  • 示例 Java 代码,显示了可以用于实现 regex 函数的 Java 代码,以及 DB2 用户定义函数的相关代码。
  • 启用,解释如何处理可以从本文下载的压缩文件,提供给您可以重新使用的完整示例。
  • 示例 SQL 语句,使用本文中所讨论的 DB2 Java 用户定义函数规定一些 SQL 查询。

Java regex 函数

第一个函数

INTEGER REGEXP_LIKE (SOURCE VARCHAR(3000),
                     REGEX VARCHAR(512),
                     MODE VARCHAR(3) )

此函数将给定正则表达式编译到具有给定模式的模式中并尝试匹配针对它的给定输入。

参数:

  • source:正则表达式所匹配的输入字符串。
  • regex:正则表达式。
  • mode:匹配模式:
    • CASE_INSENSITVE_MODE
    • DOTALL_MODE
    • MULTI_LINE_MODE

返回值:

  • 如果源与正则表达式相匹配,则值为 True,否则将返回 false
  • 指定的模式应该是正确的,否则将返回 false
  • 如果正则表达式格式不正确,则将返回 false
  • 如果源字符串是 null 或空,则将返回 0

第二个函数

VARCHAR(3000) REGEXP_REPLACE (SOURCE VARCHAR(3000), 
					REGEX VARCHAR(512), 
					REPLACEMENT VARCHAR(3000), 
					POSITION INTEGER,
					OCCURRENCE INTEGER,
					MODES VARCHAR(3))

此函数在字符串中搜索给定模式并用新的值替换它们。

参数:

  • source:在其中搜索的字符串。
  • pattern:搜索的模式。
  • Replacement:将替换所找到字符串的字符串。

    替换字符串可能包含对在之前的匹配中捕获的子序列的引用。

    每次出现的 $g 将被评估组的结果替换 (g)。$ 之后的第一个数字始终被视为组引用的一部分。如果它们可建立一个合法的组引用,则随后的数字将被合并到 g 中。只有数字 09 才被认为是组引用的可能组成部分。例如,如果第二个组与字符串 foo 相匹配,则传递替换字符串 $2bar 将导致 foobar 被附加到字符串缓冲区。

    通过在前面加上一个反斜杠 (\$),美元符号 ($) 可以作为一个文字被包括在替换字符串中。

  • startPosition:在搜索字符串中您希望开始搜索的位置。此值应该大于或等于 1。任何低于 1 的值都将导致此方法返回 null。第一个字符的位置是 1
  • occurrence:发生参数指定要替换哪些匹配。0 值意味着替换所有的值。如果指定的数字大于零,则只替换找到的发生项。如果找到的匹配项比要求的少,则不对源进行任何操作。
  • mode:匹配模式。

返回值:

这是包含被替换值替换了适当正则表达式匹配项的字符串。如果源字符串是 null 或空,则将返回 null。

第三个函数

VARCHAR(3000) REGEXP_SUBSTR (	SOURCE VARCHAR(3000),
					REGEX VARCHAR(512),
					POSITION INTEGER,
					OCCURRENCE INTEGER,
					MODES VARCHAR(3) )

此函数试图匹配并返回正则表达式针对源字符串定义的模式的特定发生项。

参数:

  • source:在其中搜索的字符串。
  • pattern:搜索的模式。
  • startPosition:在搜索字符串中您希望开始搜索的位置。此值应该大于或等于 1。任何低于 1 的值都将导致此方法返回 null。第一个字符的位置是 1
  • occurrence:发生参数指定要获得哪个匹配的值。1 值意味着要获得第一个匹配项,更高的数字意味着在以前匹配结束后开始尝试匹配 regex 的操作将一直持续到发现所有指定的匹配,然后仅返回最后的匹配项。如果找到的匹配项比要求的少,则将返回 null。
  • mode:匹配模式。

返回值

返回以前匹配项的子序列。如果没有发现匹配项或源字符串是 null 或空,则返回 null。在源字符串中,位置 0 是第一个字符。

第四个函数

INTEGER REGEXP_INSTR (	SOURCE VARCHAR(3000),
	                  REGEX VARCHAR(512),
				POSITION INTEGER,
				OCCURRENCE INTEGER,
				ROPT INTEGER,
				MODES VARCHAR(3))

此函数试图匹配正则表达式针对源字符串的模式的特定发生项。然后,其返回已匹配发生项的第一个字符或已匹配发生项后面的第一个字符在源字符串中的位置。

参数:

  • source:在其中搜索的字符串。
  • pattern:搜索的模式。
  • startPosition:在搜索字符串中您希望开始搜索的位置。此值应该大于或等于 1。任何低于 1 的值都将导致此方法返回 null。第一个字符的位置是 1
  • occurrence:发生参数指定要获得的匹配项。1 值意味着要获得第一个匹配。更高的数字意味着在以前匹配结束后开始尝试匹配 regex 的操作将一直持续到发现所有指定的匹配,然后仅返回最后的匹配项。如果找到的匹配项比要求的少,则将返回 0
  • returnOption:设置 returnOption0 以便获得匹配的第一个字符的位置。如果设置为 1,则返回匹配之后的第一个字符的位置。任何其他值将导致找不到模式并返回 0
  • Mode:匹配模式。

返回值

这是字符匹配的位置。位置 1 是源字符串中的第一个字符。如果没有发现匹配则返回 0,或者如果源字符串是 null 或空则返回 -1

匹配模式

四个 regex 函数中的每个函数可以接受的模式参数都应该是一个最多三个字符的字符串,且不属于四种可能的模式。模式 i 打开不区分大小写匹配,而 inm 打开三种选项。模式 ic 是互斥的。如果您忽略了此参数或传递空字符串,则将使用默认匹配模式。

  • 模式 i:打开不区分大小写匹配。默认为区分大小写。
  • 模式 c:打开区分大小写匹配。
  • 模式 n:使点匹配任何字符,包括新行。默认情况下,点匹配除新行以外的任何字符。
  • 模式 m:使插入符号 (^) 和美元符号 ($) 在每一行的开始和结尾相匹配,例如,在源字符串中嵌入前后换行符。默认情况下,这些只在字符串的最开始和最末尾处匹配。

如果没有指定上面的任何一种模式,返回值将总是等于 UNIX_LINES,其始终打开,这意味着在 .^$ 行为中只承认 \n 行结束符。

使用上述给定参数指定的模式应该遵循以下模式:^([nmi]{0,3})|([nmc]{0,3})$

如果指定的模式不正确,所有 regex 函数都将返回错误。

实现

Java 代码

Regexp Java 类
package com.ibm.avalanche.udf.regex;

import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;

public class Regexp
{
   private static final String CASE_INSENSITVE_MODE = "i";
   private static final String CASE_SENSITVE_MODE = "c";
   private static final String DOTALL_MODE = "n";
   private static final String MULTI_LINE_MODE = "m";

   public static int regexpInstr(String source, String pattern, int startPosition, 
   int occurrence, int returnOption, String mode) {...}
 
   public static String regexpSubstr(String source, String pattern, int startPosition, 
   int occurrence, String mode) {...}

   public static String regexpReplace(String source, String pattern, String replacement, 
   int startPosition, int occurrence, String mode) {...}

   public static int regexpLike(String source, String regex, String mode) {...}

   public static int setMode(String mode) {…}
}
函数 regexpLike
public static int regexpLike(String source, String regex, String mode)
{
   int flags = 0;

   if (  source == null || source.length()<1)
   {
      return 0;
   }

   if ((flags = setMode(mode)) == -1)
   {
      return 0;
   }
   try
   {
      Matcher matcher = Pattern.compile(regex, flags).matcher(source);

      if (matcher.find())
      {
         return 1;
      }
   }
   catch (PatternSyntaxException e)
   {
      return 0;
   }

      return 0;
}
函数 regexpReplace
public static String regexpReplace(String source, String pattern, String replacement, 
int startPosition, int occurrence, String mode)
{
   int flags = -1;

   if (  source == null || source.length()<1)
   {
      return null;
   }

   if ((replacement == null) || (startPosition-- <= 0) || ((flags = setMode(mode)) == -1))
   {
      return source;
   }

   Pattern pat;
   try
   {
      pat = Pattern.compile(pattern, flags);
   }
   catch (PatternSyntaxException e)
   {
      return source;
   }

   Matcher matcher = pat.matcher(source);
   int count = 0;
   StringBuffer sb = new StringBuffer();

   if (matcher.find(startPosition))
   {
      if (occurrence == 0)
      {
         matcher.appendReplacement(sb, replacement);
         while (matcher.find())
         {
            matcher.appendReplacement(sb, replacement);
         }
      }
      else
      {
         do
         {
            if (++count == occurrence)
            {
               matcher.appendReplacement(sb, replacement);
               break;
            }
         } while (matcher.find());
      }
      matcher.appendTail(sb);

      return sb.toString();
   }

   return source;
}
函数 regexpSubstr
public static String regexpSubstr(String source, String pattern, int startPosition, 
int occurrence, String mode)
{
   int flags = -1;

   if (  source == null || source.length()<1)
   {
      return null;
   }

   if ((startPosition-- <= 0) || ((flags = setMode(mode)) == -1))
   {
      return null;
   }

   Pattern pat;
   try
   {
      pat = Pattern.compile(pattern, flags);
   }
   catch (PatternSyntaxException e)
   {
      return null;
   }

   Matcher matcher = pat.matcher(source);
   String out = null;
   int count = 0;

   if (matcher.find(startPosition))
   {
      out = matcher.group();
      count++;
      while ((count < occurrence) && (matcher.find()))
      {
         out = matcher.group();
         count++;
      }
   }

   return (out = (count != occurrence) ? null : out);
}
函数 regexpInstr
public static int regexpInstr(String source, String pattern, int startPosition, 
int occurrence, int returnOption, String mode)
{
   int flags = -1;

   if (  source == null || source.length()<1)
   {
      return -1;
   }

   if ((returnOption != 1) && (returnOption != 0) || (startPosition-- <= 0) || 
   ((flags = setMode(mode)) == -1))
   {
      return 0;
   }

   Pattern pat;
   try
   {
      pat = Pattern.compile(pattern, flags);
   }
   catch (PatternSyntaxException e)
   {
      return 0;
   }

   Matcher matcher = pat.matcher(source);
   int out = 0;
   int count = 0;

   if (matcher.find(startPosition))
   {
      out = (returnOption == 0 ? matcher.start() : matcher.end()) + 1;
      count++;
      while ((count < occurrence) && (matcher.find()))
      {
         out = (returnOption == 0 ? matcher.start() : matcher.end()) + 1;
         count++;
      }
   }

   return (out = (count != occurrence) ? 0 : out);
}
函数 setModes
public static int setMode(String mode)
{
   int flag = Pattern.UNIX_LINES;

   try
   {
      if (!Pattern.matches("^([nmi]{0,3})|([nmc]{0,3})$", mode))
      {
         return -1;
      }

      flag |= (mode.contains(CASE_INSENSITVE_MODE) ? Pattern.CASE_INSENSITIVE : 0);
      flag |= (mode.contains(DOTALL_MODE) ? Pattern.DOTALL : 0);
      flag |= (mode.contains(MULTI_LINE_MODE) ? Pattern.MULTILINE : 0);

      // Meaningless from the code point of view but is made to insure consistency with 
      Oracle modes. This // method has to provide the CASE_SENSITIVE_MODE mode for the 
      'c' option.
      flag |= (mode.contains(CASE_SENSITVE_MODE) ? 0 : 0);
   }
   catch (PatternSyntaxException e)
   {
      return -1;
   }
   catch (NullPointerException ne)
   {
     return -1;
   }

   return flag;
}

用户定义的函数

在 DB2 中部署 JAR 文件
CALL SQLJ.INSTALL_JAR('file:C:\avalanche\db2_regex\lib\db2_regex.jar', db2_regex);
@
用户定义的函数 REGEXP_LIKE
CREATE OR REPLACE FUNCTION REGEXP_LIKE(SOURCE VARCHAR(3000), REGEX VARCHAR(512), 
MODE VARCHAR(3))

RETURNS INTEGER
FENCED 
NOT DETERMINISTIC
NO SQL
LANGUAGE JAVA
PARAMETER STYLE JAVA
EXTERNAL NAME 'db2_regex:com.ibm.avalanche.udf.regex.Regexp.regexpLike'
NO EXTERNAL ACTION
@
用户定义的函数 REGEXP_REPLACE
CREATE OR REPLACE FUNCTION REGEXP_REPLACE(SOURCE VARCHAR(3000), REGEX VARCHAR(512), 
REPLACEMENT VARCHAR(3000), POSITION INTEGER, OCCURRENCE INTEGER, MODES VARCHAR(3))

RETURNS VARCHAR(3000)
FENCED 
NOT DETERMINISTIC
NO SQL
LANGUAGE JAVA
PARAMETER STYLE JAVA
EXTERNAL NAME 'db2_regex:com.ibm.avalanche.udf.regex.Regexp!regexpReplace'
NO EXTERNAL ACTION
@
用户定义的函数 REGEXP_SUBSTR
CREATE OR REPLACE FUNCTION REGEXP_SUBSTR(SOURCE VARCHAR(3000), REGEX VARCHAR(512), 
POSITION INTEGER, OCCURRENCE INTEGER, MODES VARCHAR(3))

RETURNS VARCHAR(3000)
FENCED 
NOT DETERMINISTIC
NO SQL
LANGUAGE JAVA
PARAMETER STYLE JAVA
EXTERNAL NAME 'db2_regex:com.ibm.avalanche.udf.regex.Regexp!regexpSubstr'
NO EXTERNAL ACTION
@
用户定义的函数 REGEXP_INSTR
CREATE OR REPLACE FUNCTION REGEXP_INSTR(SOURCE VARCHAR(3000), REGEX VARCHAR(512), 
POSITION INTEGER, OCCURRENCE INTEGER, ROPT INTEGER, MODES VARCHAR(3))

RETURNS INTEGER
FENCED 
NOT DETERMINISTIC
NO SQL
LANGUAGE JAVA
PARAMETER STYLE JAVA
EXTERNAL NAME 'db2_regex:com.ibm.avalanche.udf.regex.Regexp!regexpInstr'
NO EXTERNAL ACTION
@

启用

以下步骤向您展示了如何下载并尝试示例代码。

  1. 将附加的 db2-regex.zip 文件保存到硬盘上的一个新文件夹中,例如 C:\avalanche
  2. 将压缩文件中的所有文件提取到 C:\avalanche\db2_regex
  3. 打开 C:\avalanche\db2_regex\scripts\sql\db2_regex_functions.sql
  4. 编辑脚本以满足您环境的要求。在第二行中,请变更目录名称。如果您使用 UNIX,该句法应该类似于:
    CALL SQLJ.INSTALL_JAR('file:/tmp/avalanche/db2_regex/lib/db2_regex.jar', db2_regex)
  5. 在 DB2 命令行处理器窗口中,请运行以下命令行:
    db2 connect to <my_db> user <uid> using <pwd>
    db2 set current schema='REGEXP'
    db2 -td@ -vf "C:\avalanche\db2_regex\scripts\sql\db2_regex_functions.sql"

如果您已经部署了程序包且希望再次部署它,例如,如果您已经修改了 JAVA 代码且希望尝试更新的代码,则请按以下步骤执行:

  1. 将压缩文件提取到 C:\avalanche\db2_regex
  2. 从 DB2 命令窗口处执行以下命令:
    db2 connect to <my_db> user <uid> using <pwd> db2 set current schema='REGEXP' db2 drop function REGEXP_LIKE db2 drop function REGEXP_REPLACE db2 drop function REGEXP_SUBSTR db2 drop function REGEXP_INSTR db2 call SQLJ.REMOVE_JAR(db2_regex) db2stop force db2start db2 connect to <my_db> user <uid> using <pwd> db2 set current schema='REGEXP' db2 -td@ -f C:\avalanche\db2_regex\scripts\sql\db2_regex_functions.sql

您应该检查以便确保在任何点都没有出现错误。

使用 regex 函数的 SQL 语句示例

select ID from REGEXP.REGEXP_STRINGS where 
REGEXP_LIKE(STRING, '^.EF[ ]+SAVEALIAS[ ]+[0-9]+', 'c') > 0

select ID from REGEXP.REGEXP_STRINGS where 
REGEXP_REPLACE(STRING, '^.EF[]+SAVEALIAS[ ]+[0-9]+', 'XX', 1, 1, 'c')='XX'

select ID from REGEXP.REGEXP_STRINGS where 
REGEXP_SUBSTR(STRING, '^.EF[ ]+SAVEALIAS[ ]+[0-9]+', 1, 1, 'c')='DEF SAVEALIAS 2210'

select ID from REGEXP.REGEXP_STRINGS where 
REGEXP_INSTR(STRING, '^.EF[ ]+SAVEALIAS[ ]+[0-9]+',1, 1, 1, 'c') > 0

结束语

通过本文,您已经了解了如何在您的 SQL 语句中创建 DB2 Java 用户定义的函数来处理正则表达式函数。

您看到了四个函数示例,您可以扩展、修改并添加新的函数以便帮助您更好地满足您自己的要求。

同时您可以使用可用的下载来获得一个完整的示例代码,它是一个示例且原样 可用。请自由使用、修改该代码并使它适应您的个人使用,但是请确保在任何真实的系统中使用它之前对其进行测试和验证。


下载资源


相关主题


评论

添加或订阅评论,请先登录注册

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=10
Zone=Information Management
ArticleID=630922
ArticleTitle=在 DB2 for Linux, UNIX, and Windows 9.7 上使用正则表达式和模式匹配的 Java 解决方案
publish-date=03072011