Регулярное выражение для совпадения с частичной или верблюжьей строкой? - PullRequest
3 голосов
/ 14 апреля 2009

Я бы хотел, чтобы регулярное выражение совпадало с заданной строкой или верблюжьей строкой. Например, если поисковый набор содержит строку «MyPossibleResultString», я хочу иметь возможность сопоставить ее с подобными значениями следующего:

  • MyPossibleResultString
  • MPRS
  • MPRString
  • MyPosResStr
  • M

Я также хотел бы включить сопоставление с подстановочными знаками, например ::

  • MyP * RString
  • * PosResString
  • My * Строка

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

Ответы [ 5 ]

4 голосов
/ 14 апреля 2009

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

String re = "\\b(" + query.replaceAll("([A-Z][^A-Z]*)", "$1[^A-Z]*") + ".*?)\\b";

Например, запрос MyPosResStr станет регулярным выражением:

\\b(My[^A-Z]*Pos[^A-Z]*Res[^A-Z]*Str[^A-Z]*.*?)\\b

Затем вы используете это регулярное выражение для сопоставления, используя метод Matcher.find, чтобы получить что-то вроде этого:

public static String matchCamelCase(String query, String str) {
    query = query.replaceAll("\\*", ".*?");
    String re = "\\b(" + query.replaceAll("([A-Z][^A-Z]*)", "$1[^A-Z]*") + ".*?)\\b";

    System.out.println(re);
    Pattern regex = Pattern.compile(re);

    Matcher m = regex.matcher(str);

    if  (m.find()) {
        return m.group();
    } else return null;
}

Это вернет первое совпадение с вашим запросом верблюда в строке str.

РЕДАКТИРОВАТЬ: я добавил строку для обработки подстановочных знаков, так как в моем уставшем ступоре я не ценил их необходимость

2 голосов
/ 14 апреля 2009

Как сказал Данбрук, вы должны генерировать новое регулярное выражение для каждого нового запроса. Этот код должен делать то, что вы хотите.

public Pattern queryToPattern(String query) {
    StringBuilder sb = new StringBuilder();
    char[] chars = query.toCharArray();
    boolean incamel = false;
    for (int i=0; i < chars.length; i++) {
        if (chars[i] == '*') {
                            if (!incamel)
                    sb.append(".*");
        } else if (Character.isUpperCase(chars[i])) {
            if (incamel) {
                sb.append(".*");
            }
            sb.append(chars[i]);
            incamel = true;
        } else {
            sb.append(chars[i]);
        }

    }
    sb.append(".*");
    return Pattern.compile(sb.toString());
}

Запрос: MyP * RString

Создает шаблон: My. * P. * R. * String. *

1 голос
/ 14 апреля 2009

Невозможно сделать это с помощью одного регулярного выражения. Вам нужно будет построить регулярное выражение на основе ввода и использовать его для поиска. Легко видеть, что вы не можете использовать одно регулярное выражение - пользователь может искать любую строку (в оболочке cammel), и поэтому ваше регулярное выражение должно соответствовать любой строке (в оболочке cammel), но это уже не поиск.

0 голосов
/ 10 октября 2010

Отличный ответ Иль-Бхимы, но я считаю, что этот код работает лучше для меня (простите мой C #, но он такой же):

pattern = Regex.Escape(pattern);
pattern = pattern.Replace(@"\*", ".*?");
pattern = Regex.Replace(pattern, "([A-Z][^A-Z]*)", "$1[^A-Z]*?") + ".*";

Обратите внимание на «. *» В конце, который допускает неполные фразы «startof» (также позволяет не указывать все заглавные буквы) Кроме того, звездочка после сопоставителя «[^ AZ] *» исправляет проблемы, подобные q4 в ответе инструментария, где строчные буквы указывались после заглавных (они должны появляться непосредственно после заглавной буквы, а не перед следующей один).

0 голосов
/ 14 апреля 2009

Вы можете попробовать что-то вроде:

class RegexTransformer {
    public String fromQuery(String query) {
        StringBuilder sb = new StringBuilder();
        sb.append("^");
        sb.append(query.replaceAll("(\\p{Upper}(?!\\p{Lower}))",
                "$1\\\\p{Alpha}*?"));
        sb.append("$");
        return sb.toString();
    }
}

См. Pattern API для описания отрицательных прогнозных утверждений (?!pat), классов символов POSIX \p{class} и неохотных квантификаторов *?.

Пример теста:

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;

import org.junit.Test;

public class RegexTransformerTest {

    private RegexTransformer rt = new RegexTransformer();

    @Test
    public void testQueries() {
        String in = "MyPossibleResultString";
        String q1 = "MyPossibleResultString";
        String q2 = "MPRS";
        String q3 = "MPRString";
        String q4 = "MyPosResStr"; // this wont work
        String q5 = "M";

        test(in, q1, "^MyPossibleResultString$");
        test(in, q2, "^M\\p{Alpha}*?P\\p{Alpha}*?R\\p{Alpha}*?S\\p{Alpha}*?$");
        test(in, q3, "^M\\p{Alpha}*?P\\p{Alpha}*?R\\p{Alpha}*?String$");
        test(in, q5, "^M\\p{Alpha}*?$");
    }

    private void test(String in, String query, String expected) {
        assertEquals("transform", expected, rt.fromQuery(query));
        assertTrue("match", in.matches(rt.fromQuery(query)));
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...