正则表达式 - 使用正则表达式搜索另一个字符串中的特定字符串

时间:2014-01-18 18:45:40

标签: java regex string search pattern-matching

我想在字符串中搜索标识符。标识符可以有变化

REF964758362562
REF964-758362-562
964758362562
964-758362-562

标识符可以位于字符串中的任何位置,也可以位于其自身上。例如:

Lorem ipsum REF964-758362-562
Lorem ipsum ABCD964-758362-562 lorem ipsum
Lorem ipsum REF964-758362-562 lorem ipsum
REF964-758362-562 Lorem ipsum 1234-123456-22
Lorem ipsum 964-758362-562 lorem ipsum
REF964758362562
REF964-758362-562
964758362562
964-758362-562

当在标识符中使用连字符/短划线字符时,连字符将始终显示在示例中所示的第3和第9位之后。

这是我提出的,但我怀疑正则表达式太长,可能会缩短。这也适用于 标识符不在字符串的开头。任何提示/想法?

^[A-Z]*REF[A-Z]*([12]\d{3})(\d{6})(\d{2})$|^([12]\d{3})(\d{6})(\d{2})[A-Z]*REF[A-Z]*|^([12]\d{3})(\d{6})(\d{2})$

我已将它们分组,因为一旦我提取了标识符,我想添加连字符,如果标识符没有连字符。例如,如果 提取的标识符为964758362562,我想将其另存为964-758362-562

以下是我运行的一些测试,因为你可以看到很多测试都没有匹配

testRegex = "^[A-Z]*REF[A-Z]*([12]\\d{3})(\\d{6})(\\d{2})$|^([12]\\d{3})(\\d{6})(\\d{2})[A-Z]*REF[A-Z]*|^([12]\\d{3})(\\d{6})(\\d{2})$";
        PATTERN = Pattern.compile(testRegex, Pattern.CASE_INSENSITIVE);

        m = PATTERN.matcher("Lorem ipsum REF964-758362-562");
        if(m.matches()) {
            System.out.println("Match = " + m.group());
        }else{
            System.out.println("No match");
        }

        m = PATTERN.matcher("REF964-758362-562 Lorem ipsum 1234-123456-22");
        if(m.matches()) {
            System.out.println("Match = " + m.group());
        }else{
            System.out.println("No match");
        }

        m = PATTERN.matcher("Lorem ipsum 964-758362-562 lorem ipsum");
        if(m.matches()) {
            System.out.println("Match = " + m.group());
        }else{
            System.out.println("No match");
        }

        m = PATTERN.matcher("Lorem ipsum ABCD964-758362-562 lorem ipsum");
        if(m.matches()) {
            System.out.println("Match = " + m.group());
        }else{
            System.out.println("No match");
        }

        m = PATTERN.matcher("REF964758362562");
        if(m.matches()) {
            System.out.println("Match = " + m.group());
        }else{
            System.out.println("No match");
        }

        m = PATTERN.matcher("REF964-758362-562");
        if(m.matches()) {
            System.out.println("Match = " + m.group());
        }else{
            System.out.println("No match");
        }

        m = PATTERN.matcher("964758362562");
        if(m.matches()) {
            System.out.println("Match = " + m.group());
        }else{
            System.out.println("No match");
        }

        m = PATTERN.matcher("964-758362-562");
        if(m.matches()) {
            System.out.println("Match = " + m.group());
        }else{
            System.out.println("No match");
        }

输出

No match
Match = Not known
No match
No match
No match
No match
No match
No match
No match
No match

4 个答案:

答案 0 :(得分:4)

使用此正则表达式:

(REF)?964-?758362-?562

?使前一组可选,零或一次出现。

“REF”是可选的,短划线是可选的。

要强制两个破折号都在那里,请使用此正则表达式

(REF)?964-758362-562|(REF)?964758362562

答案 1 :(得分:2)

看起来标识符遵循这种一般模式:

  • 可选REF
  • 3位数
  • 可选连字符
  • 6位数
  • 连字符,如果第一个连字符存在。如果不是连字符。
  • 3位数

在这种情况下,这种模式将起作用

(?>REF)?(\\d{3}+)(-?)(\\d{6}+)\\2(\\d{3}+)

打破模式:

  • (?>REF)?一个匹配“REF”的原子组,可选
  • (\\d{3}+)占有3位数,占有(第1组)
  • (-?)捕获可选连字符(第2组)
  • (\\d{6}+)占有6位数,占有(第3组)
  • \\2反向引用第二组中捕获的内容
  • (\\d{3}+)占有3位数,占有(第4组)

漂亮的技巧是捕获可选的连字符然后反向引用它,这样如果第一个连字符存在则第二个必须是;相反,如果第一个连字符不存在,则第二个连字符不能存在。

Java中的测试用例:

public static void main(String[] args) throws Exception {
    final String[] test = {"Lorem ipsum REF964-758362-562",
        "Lorem ipsum ABCD964-758362-562 lorem ipsum",
        "REF964-758362-562 Lorem ipsum 1234-123456-22",
        "Lorem ipsum 964-758362-562 lorem ipsum",
        "REF964758362562",
        "REF964-758362-562",
        "964-758362562",
        "964758362-562",
        "964758362562",
        "964-758362-562"};
    final Pattern patt = Pattern.compile("(?>REF)?(\\d{3}+)(-?)(\\d{6}+)\\2(\\d{3}+)");
    final MessageFormat format = new MessageFormat("{0}-{1}-{2}");
    for (final String in : test) {
        final Matcher mat = patt.matcher(in);
        while (mat.find()) {
            final String id = format.format(new Object[]{mat.group(1), mat.group(3), mat.group(4)});
            System.out.println(id);
        }
    }
}

输出:

964-758362-562
964-758362-562
964-758362-562
964-758362-562
964-758362-562
964-758362-562
964-758362-562
964-758362-562

您的主要问题是使用Matcher.matches(),需要整个输入才能匹配模式。你真正想要的是找到输入中的 模式。为此目的,有while(Matcher.find())成语 - 它依次在输入中找到模式的每次出现。

答案 2 :(得分:2)

其他答案的想法非常好,但如果您不想接受只有123-123456123这样的短划线的标识符,您应该使用类似

的内容
  (REF)?(\\d{3}-\\d{6}-\\d{3}|\\d{12})
//which means 
// REF 
// and after that numbers in form
//      XXX-XXXXXX-XXX      OR   XXXXXXXXXXXX
// where X represents any digit

你可以用\b这个正则表达式包围,这是一个单词边界,以确保它是单独的单词,而不是其他单词的一部分。

答案 3 :(得分:1)

您可能希望使用m.find()代替m.matches()

    testRegex = "(?:REF)?(\\d{3})(-?)(\\d{6})\\2(\\d{3})";
    PATTERN = Pattern.compile(testRegex, Pattern.CASE_INSENSITIVE);
    m = PATTERN.matcher(
            "Lorem ipsum REFREF964-758362-562\n" +
            "Lorem ipsum ABCD964-758362-562 lorem ipsum\n" +
            "Lorem ipsum REF964-758362-562 lorem ipsum\n" +
            "REF964-758362-562 Lorem ipsum 1234-123456-22\n" +
            "Lorem ipsum 964-758362-562 lorem ipsum\n" +
            "REF964758362562\n" +
            "REF964-758362-562\n" +
            "964758362562\n" +
            "964-758362-562");
    while(m.find()) {
        System.out.println(m.group(1)+"-"+m.group(3)+"-"+m.group(4));
    }