2014-01-18 206 views
0

我想搜索字符串作为标识符。标识符可以有4个变体正则表达式 - 使用正则表达式在另一个字符串中搜索特定的字符串

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 

当连字符/破折号字符在标识符中使用的,连字符将始终显示如实施例中所示的第三和第九位之后。

下面是我想出的,但我怀疑正则表达式变得太长,它可能会缩短。当 标识符不在字符串的开头时,这也可以很好地工作。任何提示/想法?

^[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 

回答

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())成语 - 它会依次查找输入中的每个模式。

+0

这将接受'123-123456123'。不知道这是OP想要的。 – Pshemo

+0

@Pshemo你说得对,OP可能不想要。莱梅向那里进行了反向引用。 –

+0

如果使用连字符/短划线,则应该存在两个破折号。 – ziggy

4

使用这个表达式:

(REF)?964-?758362-?562 

的?使前面的组是可选的,无论是零还是一次出现。

“REF”是可选的,破折号是可选的。

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

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

这也将接受只有一个连字符/短划线的标识符。也似乎应该有数字类'\ d',而不是在正则表达式中的具体数字。 – Pshemo

+0

有趣的是,我从来没有见过以前使用过的具体数字。这些表达如何翻译? – ziggy

+0

@Pshemo,OP说他正在寻找那个特定的标识符,所以我认为具体的数字是可取的。不过,我同意,不接受只有一个破折号的标识符可能会更好。 –

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)); 
    } 
+0

是的,我正在寻找,谢谢 – ziggy

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包围这个正则表达式来确保它是单独的单词,而不是其他单词的一部分。

+0

我认为我更喜欢我漂亮的后台参考:第。 –

+0

@BoristheSpider是'\\ 2'似乎解决了这个问题。拥有量词也可以提高性能,但现在我没有把重点放在那:) – Pshemo

相关问题