正则表达方法

时间:2011-02-11 14:08:39

标签: java regex

我正在尝试提供一种函数,该函数可以为指定的字符串生成可能的数据库匹配,其中大多数这些指定的字符串不能轻易匹配,因为它们处于不同的命名形式,例如电影的首字母缩略词。数据库值仅在此阶段使用全名。到目前为止我所提出的是一个函数,它生成一个模式,每个单词的首字母由数据库候选者分隔。*

pkgName matched:
The.Fighter.2010.DVDRip.XviD.AC3-TiMPE,
for pattern: .*0.*M.*, title: 007
Moonraker   pkgName matched:
The.Fighter.2010.DVDRip.XviD.AC3-TiMPE,
for pattern: .*1.*A.*M.*, title: 12
Angry Men  pkgName matched:
The.Fighter.2010.DVDRip.XviD.AC3-TiMPE,
for pattern: .*3.*, title: 300 
pkgName matched:
The.Fighter.2010.DVDRip.XviD.AC3-TiMPE,
for pattern: .*A.*P.*, title: A
Prophet  pkgName matched:
The.Fighter.2010.DVDRip.XviD.AC3-TiMPE,
for pattern: .*A.*, title: Adaptation 
pkgName matched:
The.Fighter.2010.DVDRip.XviD.AC3-TiMPE,
for pattern: .*A.*, title:
Adventureland  pkgName matched:
The.Fighter.2010.DVDRip.XviD.AC3-TiMPE,
for pattern: .*A.*, title: Amelie 
pkgName matched:
The.Fighter.2010.DVDRip.XviD.AC3-TiMPE,
for pattern: .*A.*P.*, title: American
Psycho

问题是这种方法产生了太多不需要的建议匹配(在我之前的例子中都是不需要的)。任何人都可以建议一个更好的方法,以削减不必要的这些匹配?正则表达式是否适用于此?

public ArrayList<Movie> databaseMatches(String pkgName) {
    Connection conn = getConnection();
    ArrayList<Movie> dbMatches = new ArrayList<Movie>();
    try {
        for (Movie dbTitle : getDatabaseMovies(conn)) {
            Pattern p = Pattern.compile(createTitlePattern(dbTitle.getTitle()));
            Matcher m = p.matcher(pkgName);
            if (m.find()) {
                System.out.println("pkgName matched: " + pkgName + ", for pattern: " + createTitlePattern(dbTitle.getTitle()) + ", title: " + dbTitle.getTitle());
                dbMatches.add(dbTitle);
            }
        }
    } catch (SQLException e) {
        e.printStackTrace();
    }
    return dbMatches;
}

private String createTitlePattern(String dbTitle) {

    // System.out.println("dbTitle: " + dbTitle + "split(' ')");

    String titleParts[] = dbTitle.split(" ");
    String searchPattern = ".*";
    for (int i = 0; i < titleParts.length; i++) {
        char c = titleParts[i].charAt(0);
        searchPattern += (c + ".*");
    }
    // System.out.println("pattern produced: " + searchPattern);
    return searchPattern;
}

编辑:我遇到过每个首字母缩略词字母之间带有各种字符的字符串实例,所以我认为这种模式是合适的。

3 个答案:

答案 0 :(得分:1)

.*x.*y.*z.*形式的正则表达式表示“我们可以按顺序找到x,y,z的任何字符串,由任意数量的任何字符分隔”,并且没有迹象表明x,y或者z必须是单个单词的第一个字母。

在首字母缩写之前,你必须把一个字符类放在你期望的所有字符分隔符上。

您可以使用预定义的\W字符类将所有非单词字符视为字词分隔符。

单词字符为A-Za-z0-9_(下划线)。所有其他人都是非文字字符。

如果此功能适合您,请将".*"替换为".*\W"

答案 1 :(得分:1)

由于您对数据格式的标准很少,因此您可能需要使用稍微不同的方法,这可能会也可能不会,这取决于应用程序的数据/吞吐量需求的大小。一个建议是从全文匹配开始,只有在未能产生结果的情况下才会转移到更广泛的搜索或其他变体。

使用前面的示例,您可以从完整的关键字搜索开始:

.*American.*Psycho.*

如果不能产生结果,请尝试纯粹的首字母缩略词搜索

.*AP.*

如果单个关键字搜索失败

.*((American)|(Psycho)).*

然后进入混合关键字/缩写搜索

.*(A|(American)).*(P|(Psycho))

等。同样,根据搜索运行的速度/运行速度需要多快,这种方法可能会受到严重阻碍。

如果这是不可接受的,您可以尝试使用上面的单个“松散”模式,并尽可能尝试允许完整的单词匹配,并最小化关键字之间的分组。

.*(A[merican]*)(.*?)(P[sycho]*)

请注意,我们使用字符类(方括号)而不是常规分组(圆括号),以允许在剩余标题上进行部分匹配。即前一个匹配“Amer.Psy。”。然后根据您获得的匹配,您可以进一步检查分组以消除误报。例如,如果组1仅匹配“A”,则可能期望组2为空,或者仅包含非字母数字,如果不是,则将其视为误报。

答案 2 :(得分:1)

为了匹配不可预测的缩写,您需要使用比First Letters更好的技术。 Stack Overflow上的这篇文章有一些想法,包括用于匹配两个单词之间距离的替代算法:

Regex - Matching Abbreviations of a Word