2017-07-27 109 views
1

我已经做了一堆搜索,但我很糟糕的正则表达式和我的谷歌福在这种情况下,不强。与错误检查正则表达式

场景:

在推送通知,我们通过包含一个9位数的内容ID的URL。

实例网址:http://www.something.com/foo/bar/Some-title-Goes-here-123456789.html(123456789在此方案中的内容ID)

当前正则表达式来解析内容ID:

public String getContentIdFromPathAndQueryString(String path, String queryString) { 
     String contentId = null; 
     if (StringUtils.isNonEmpty(path)) { 
      Pattern p = Pattern.compile("([\\d]{9})(?=.html)"); 
      Matcher m = p.matcher(path); 
      if (m.find()) { 
       contentId = m.group(); 
      } else if (StringUtils.isNonEmpty(queryString)) { 
       p = Pattern.compile("(?:contentId=)([\\d]{9})(?=.html)"); 
       m = p.matcher(queryString); 
       if (m.find()) { 
        contentId = m.group(); 
       } 
      } 
     } 

     Log.d(LOG_TAG, "Content id " + (contentId == null ? "not found" : (" found - " + contentId))); 
     if (StringUtils.isEmpty(contentId)) { 
      Answers.getInstance().logCustom(new CustomEvent("eid_url") 
        .putCustomAttribute("contentId", "empty") 
        .putCustomAttribute("path", path) 
        .putCustomAttribute("query", queryString)); 
     } 

     return contentId; 
    } 

问题: 这做这项工作,但有一个特定的错误我需要考虑的情景。

无论是谁创建推送可能会输入错误的长度的内容ID,我们需要抓住它,所以假设它可以是任意数字的数字......标题也可以包含数字,这是烦人的。内容ID将总是后面跟着“.html”

+0

更换'{9}'和'+'(出现一次或多次)。 –

+0

会在内容ID之前绕过标题部分中的任何数字吗? – Psest328

+0

查看https://regex101.com/r/3PamZj/1 –

回答

1

虽然这里的基本答案只是“替换{9}限制量词匹配正好9次出现与+量词匹配1+次出现”,有两种模式可以是改进。

未转义的点应该在模式中转义以匹配文字点。

如果您没有重叠匹配,则无需在捕获组之前使用正向前视功能,只需保留捕获组并抓取值即可。

non-capturing group (?:...)仍然是一个耗时图案,并且(?:contentId=)等于contentId=(您可能除去(?:))。

有没有必要包装一个character class内的单个原子,使用\\d而不是[\\d][\\d]实际上是误解的来源,有些人可能认为它是一个分组构造,并且可能会尝试将替代序列放入方括号中,而[...]匹配单个字符。

所以,你的代码可以像

 Pattern p = Pattern.compile("(\\d+)\\.html");  // No lookahead, + instead of {9} 
     Matcher m = p.matcher(path); 
     if (m.find()) { 
      contentId = m.group(1);      // (1) refers to Group 1 
     } else if (StringUtils.isNonEmpty(queryString)) { 
      p = Pattern.compile("contentId=(\\d+)\\.html"); 
      m = p.matcher(queryString); 
      if (m.find()) { 
       contentId = m.group(1); 
      } 
     }