Подход регулярного выражения - PullRequest
1 голос
/ 11 февраля 2011

Я пытаюсь придумать функцию, которая производит возможные совпадения базы данных для указанных строк, где большинство этих указанных строк не могут быть легко сопоставлены, так как они имеют разные формы именования, например, аббревиатуры для фильмов. Значения базы данных используют только полные имена на этом этапе. До сих пор я придумал функцию, которая генерирует шаблон, в котором начальная буква каждого слова отделена от * кандидатами в базу данных:

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 ]

1 голос
/ 11 февраля 2011

Поскольку у вас так мало критериев в отношении формата ваших данных, вам может потребоваться использовать несколько иной подход, который может быть или не быть осуществимым в зависимости от размера ваших данных / потребности в пропускной способности для приложения. Одно из предложений - начать с полнотекстового соответствия и только в том случае, если это не дает результатов, перейти к более обобщенному поиску или другим вариантам.

В предыдущем примере вы можете начать с полного поиска по ключевым словам:

.*American.*Psycho.*

, и если это не дает результатов, попробуйте поиск по чистой аббревиатуре

.*AP.*

и, если это не удается, поиск по одному ключевому слову

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

и затем поиск по смешанному ключевому слову / сокращению

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

и т.д.. Опять же, этот подход может быть значительно затруднен в зависимости от того, насколько быстро выполняются поиски / насколько быстро они нужны.

Если это неприемлемо, вы можете попробовать использовать один «свободный» шаблон, как указано выше, с модификациями попыток разрешить полное совпадение слов, если это возможно, а также минимизировать группировку между ключевыми словами.

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

Обратите внимание, что мы используем класс символов (квадратные скобки) вместо обычной группировки (круглые скобки), чтобы разрешить частичное совпадение с оставшимся заголовком. то есть предыдущий будет соответствовать "Amer. Psy.". Затем, основываясь на полученных совпадениях, вы можете провести дальнейшую проверку группировки, чтобы исключить ложные срабатывания. Например, если группа 1 соответствует только «A», вы можете ожидать, что группа 2 будет пустой или содержать только не буквенно-цифровые символы, а если этого не произойдет, вы отклоните ее как ложное срабатывание.

1 голос
/ 11 февраля 2011

Чтобы соответствовать непредсказуемым сокращениям, вам нужно использовать лучшую технику, чем первые буквы. В этом посте о переполнении стека есть несколько идей, включая альтернативные алгоритмы для сопоставления расстояния между двумя словами:

Regex - соответствующие сокращения слова

1 голос
/ 11 февраля 2011

Регулярное выражение в форме .*x.*y.*z.* означает «любую строку, в которой мы можем найти x, y, z в этом порядке, разделенные любым количеством любого символа», и нет никаких признаков того, что x, y илиz должен быть на первой букве отдельного слова.

Перед инициалами необходимо поместить символьный класс со всеми ожидаемыми символами в качестве разделителя слов.

Вы можете использовать предопределенный \W класс символов, чтобы рассматривать все несловесные символы как разделитель слов.

Символами слова являются A-Z, a-z, 0-9 и _ (подчеркивание).Все остальные не являются символами слов.

Если вам это подходит, замените ".*" на ".*\W".

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...