Регулярное выражение Java два вопросительных знака (??)

Я знаю, что /? означает, что / является необязательным. Итак " игрушки?"будет соответствовать как игрушке, так и игрушкам. Я понимаю, что если я сделаю его ленивым и использую "игрушки??"Я буду соответствовать и игрушке и игрушкам и всегда возвращать игрушку. Итак, быстрый тест:

private final static Pattern TEST_PATTERN = Pattern.compile("toys??", Pattern.CASE_INSENSITIVE);
public static void main(String[] args) {
    for(String arg : args) {
        Matcher m = TEST_PATTERN.matcher(arg);
        System.out.print("Arg: " + arg);
        boolean b = false;
        while (m.find()) {
            System.out.print(" {");
            for (int i=0; i<=m.groupCount(); ++i) {
                System.out.print("[" + m.group(i) + "]");
            }
            System.out.print("}");
        }
        System.out.println();
    }
}

Да, похоже, он работает так, как ожидалось

java -cp .. regextest.RegExTest toy toys
Arg: toy {[toy]}
Arg: toys {[toy]}

теперь измените регулярное выражение на " игрушки??2 " и он по-прежнему соответствует toys2 и toy2. В обоих случаях он возвращает всю строку без удаления s. Есть ли какие-либо функциональные разница между поиском " игрушек?2" и "игрушки??2".

причина, по которой я спрашиваю, заключается в том, что я нашел пример, подобный следующему:

private final static Pattern TEST_PATTERN = Pattern.compile("</??tag(s+?.*?)??>", Pattern.CASE_INSENSITIVE);

и хотя я не вижу очевидной причины для использования ?? чем ? Я подумал, что, возможно, первоначальный автор (который мне неизвестен) может знать что-то, чего я не знаю, я ожидаю позже.

1 ответов


?? лентяй, а ? жаден.

дано (pattern)??, он сначала проверит пустую строку, а затем, если остальная часть шаблона не может совпадать, он будет проверять pattern.

в противоположность (pattern)? будет проверить для pattern во-первых, затем он будет проверять пустую строку на backtrack.


теперь измените регулярное выражение на " игрушки??2 " и он по-прежнему соответствует toys2 и toy2. В обоих случаях он возвращает всю строку без s удален. Есть ли функциональная разница между поиском "игрушек"?2" и "игрушки??2".

разница в порядке поиска:

  • "toys?2" ищет toys2, потом toy2
  • "toys??2" ищет toy2, потом toys2

но для случая этих 2 шаблонов результат будет одинаковым независимо от входной строки, так как продолжение 2 (после s? или s??) должно быть совпадение.


что касается шаблона, который вы нашли:

Pattern.compile("</??tag(\s+?.*?)??>", Pattern.CASE_INSENSITIVE)

и ?? можно изменить на ? не влияя на результат:

  • / и t (in tag) составляют взаимоисключающие. Вы либо одно, либо другое.
  • > и \s также взаимоисключающие. По крайней мере, 1 в \s+? важно для этого вывода: результат может быть другой иначе.

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

кстати, двигатель может столкнуться с какой-то дорогой попыткой возврата из-за \s+?.*? когда вход имеет <tag затем много пробелов без > в любом месте рядом.