2011-08-18 39 views
4

我有一个非常长的字符串,我想解析子字符串“ISBN”后面出现的数字值。但是,这个13位数字的分组可以通过“ - ”字符进行不同的排列。示例:(这些都是有效的ISBN)123-456-789-123-4,或​​或OR 12-34-56-78-91-23-4。本质上,我想在潜在的ISBN上使用正则表达式模式匹配器来查看是否存在有效的13位ISBN。我如何“忽略”“ - ”字符,所以我可以只用\d{13}模式的正则表达式?我的功能:用正则表达式提取ISBN

public String parseISBN (String sourceCode) { 
    int location = sourceCode.indexOf("ISBN") + 5; 
    String ISBN = sourceCode.substring(location); //substring after "ISBN" occurs 
    int i = 0; 
    while (ISBN.charAt(i) != ' ') 
    i++; 
    ISBN = ISBN.substring(0, i); //should contain potential ISBN value 
    Pattern pattern = Pattern.compile("\\d{13}"); //this clearly will find 13 consecutive numbers, but I need it to ignore the "-" character 
    Matcher matcher = pattern.matcher(ISBN); 
    if (matcher.find()) return ISBN; 
    else return null; 
} 
+2

我的建议是只替换'-'什么也没有。然后使用您的ISBN检查功能。如果它是正确的,你可以使用你需要的任何一个。 –

+0

一些很好的正则表达式的答案,我肯定会用一个,因为它会赶上所有有效ISBN格式 - 但我只是想指出的是,在ISBN的破折号不要随意插入;只有某些组合是有效的。 (当然,你不是试图验证数字的形式,只是得到数字) –

回答

8
  • 选择1:

    pattern.matcher(ISBN.replace("-", "")) 
    
  • 备选方案2:喜欢的东西

    Pattern.compile("(\\d-?){13}") 
    
第二替代的

演示:

String ISBN = "ISBN: 123-456-789-112-3, ISBN: 1234567891123"; 

Pattern pattern = Pattern.compile("(\\d-?){13}"); 
Matcher matcher = pattern.matcher(ISBN); 

while (matcher.find()) 
    System.out.println(matcher.group()); 

输出:

123-456-789-112-3 
1234567891123 
+1

你很难找到更好的可读性和代码效率的组合。您可以提高效率,但会失去很多可读性。 – corsiKa

+0

效率如何如此呢?我将会潜在地调用这个函数几千次,所以任何东西都会有帮助... –

+0

一些正则表达式可以被编译成令人讨厌的后台跟踪例程。这个可能会非常有效。明显的选择是在for循环中通过“手动”字符串。如果你最终这两种方法的比较,请报告你的结果回到这里......很想听到:-) – aioobe

0

尝试剥离破折号出来,正则表达式,新的字符串

5

尝试这种情况:

Pattern.compile("\\d(-?\\d){12}") 
+1

+1最佳答案呢。但是我会在每一端添加一个'\ b'字边界锚。 – ridgerunner

3

使用此图案:

Pattern.compile("(?:\\d-?){13}") 

和钢带从发现的ISBN号

1

所有破折号可以剥离出与字符串操作的破折号,或者你可以使用这个:

"\\b(?:\\d-?){13}\\b" 

它确保该字符串的好处不以-开始或结束。

2

通过识别所有内容的模式和数字之间的可选破折号在一个步骤中执行此操作。不需要摆弄ISBN偏移+子字符串。

ISBN(\d(-?\d){12}) 

如果您想要原始数字,请从第一个匹配的子组中剥离破折号。 我不是一个Java人,所以我不会告诉你代码。

2

如果你要打电话的方法很多,你可以做的最好的事情是而不是编译它里面的模式。否则,每次调用该方法时,都会花费更多时间创建正则表达式,而不是实际搜索它。

但是在再次查看您的代码后,我认为您遇到了更大的问题,性能方面。定位“ISBN”然后创建子字符串以应用正则表达式的所有业务是完全不必要的。让正则表达式做这件事。这是他们的目的。下面的正则表达式找到“ISBN”定点以下13位数字,如果他们有:

static final Pattern isbnPattern = Pattern.compile(
    "\\bISBN[^A-Z0-9]*+(\\d(?:-*+\\d){12})", Pattern.CASE_INSENSITIVE); 

[^A-Z0-9]*+吃掉任何可能的“ISBN”和第一个数字间出现的字符。所有格量词(*+)可防止不必要的回溯;如果下一个字符不是数字,那么正则表达式引擎会立即退出匹配尝试并继续扫描另一个“ISBN”实例。

我用于可选的连字符另一个所有格量词,加上用于重复的部分的非捕获组((?:...));与其他响应者正在使用的捕获组相比,它们的性能增益略微有所提高。但是我为整个数字使用了一个捕获组,所以它可以很容易地从总体匹配中提取出来。有了这些变化,您的方法可以简化为:

public String parseISBN (String source) { 
    Matcher m = isbnPattern.matcher(source); 
    return m.find() ? m.group(1) : null; 
} 

...而且它也更有效率。请注意,我们尚未解决字符串如何进入内存。如果你自己在做I/O,那么在这方面也可能会有显着的性能提升。