Есть такое РВ: ^(%[\\dA-F]{2}|[\\w\\-.~!$&'()*+,;=])*$
Оно используется для проверки правильности части hostname в URL.
Для более быстрого понимания объясню его суть: любое количество сочетаний закодированных символов (например %AA) или любого одиночного символа из множества -.~!$&'()*+,;= , включая "слвесные" символы. По-скольку теоретически в URL могут встречаться как закодированные так и незакодированные символы, то используется "альтернация" посредством |.
Вот из-за нее то и происходит StackOverflowError , когда мы пытаемся проверить строку на соответствие РВ, в случаях когда длина строки превышает примерно 1500.
Вопрос в том, можно ли как-то избежать использования палки "|" в данном случае?
Ну и конечно альтернативные предложения принимаются
Re: java.lang.StackOverflowError на Regexp
От:
Аноним
Дата:
16.05.13 18:24
Оценка:
Погонял и так и сяк — ничего не выходит. Порежь на куски и проверь по отдельности.
Re[2]: java.lang.StackOverflowError на Regexp
От:
Аноним
Дата:
16.05.13 19:05
Оценка:
Здравствуйте, Аноним, Вы писали:
А>Погонял и так и сяк — ничего не выходит. Порежь на куски и проверь по отдельности.
Или в 2 прохода гонять
— 1й проход замена %[\dA-F]{2} на какой-нибудь символ из второго набора, но не цифра или A-F, например !
— 2й проход — поиск уже по второму набору
Здравствуйте, hl-man, Вы писали:
HM>Вопрос в том, можно ли как-то избежать использования палки "|" в данном случае?
HM>Ну и конечно альтернативные предложения принимаются
У Вас же взаимоисключающие условия добавте жадные плюсики и наслаждайтесь:
PAS>>^((%[\\dA-F]{2})+|[\\w\\-.~!$&'()*+,;=]+)*$ PAS>>У меня выдерживает 22000 символов стабильно. А>У меня на 2000 валидных символах + 1 невалидный в конце (например, @) повисает на больше чем на минуту, потом я его вырубаю
Не проще ли на pure Java переписать?
Здравствуйте, Аноним, Вы писали:
А>У меня на 2000 валидных символах + 1 невалидный в конце (например, @) повисает на больше чем на минуту, потом я его вырубаю
У меня 22000 валидных + 1 невалидный обрабатывается 60мс без оптимизаций В любом случае можно попробовать вылечить с помощью possessive quantifiers, которые поддерживаются в Java, чтоб бектрекинг отрубить.
Здравствуйте, Blazkowicz, Вы писали:
B>Здравствуйте, Аноним, Вы писали:
PAS>>>^((%[\\dA-F]{2})+|[\\w\\-.~!$&'()*+,;=]+)*$ PAS>>>У меня выдерживает 22000 символов стабильно. А>>У меня на 2000 валидных символах + 1 невалидный в конце (например, @) повисает на больше чем на минуту, потом я его вырубаю B>Не проще ли на pure Java переписать?
Пусть переписывает
Ещё как вариант можно обратную задачу решать — искать хоть один невалидный символ — по идее будет быстрее
Здравствуйте, hl-man, Вы писали:
HM>В итоге решение было таким:
HM>^(?>%[\dA-F]{2}|[\w-.~!$&'()*+,;=])*$
HM>Спасибо всем откликнувшимся ^_^
По сути ты избавился от части бектрекинга атомарными группами. Possessive quantifiers сделает тоже самое и быстрее. Кстати, если у тебя символы встречаются чаще чем %ХХ, то стоит их поменять местами в регулярке.
Здравствуйте, PAS_Tor, Вы писали: PAS>Possessive quantifiers сделает тоже самое и быстрее.
Гм... Возможно. По правде говоря я не очено то в них "въехал", потому и задействовал атомарные группы Надо изучить вопрос. PAS>Кстати, если у тебя символы встречаются чаще чем %ХХ, то стоит их поменять местами в регулярке.
Тоже учту. Спасибо за совет.
Здравствуйте, hl-man, Вы писали:
PAS>>Possessive quantifiers сделает тоже самое и быстрее. HM>Гм... Возможно. По правде говоря я не очено то в них "въехал", потому и задействовал атомарные группы Надо изучить вопрос.
Расчёт на то, что если ты встретил незакодированный символ, то с очень большой вероятностью следующий символ тоже будет не закодирован. То же самое с "процентными" группами. Так что имеет смысл выбирать сначала повторения, без необходимости обращаться к |.
Есть три нотации повторений:
Жадные – .+ – сначала отбирают всё что могут, потом, если нужно, потихоньку отдают символы строке назад (бектрекинг)
/<.+>/.exec("Some <tag>text</tag> here")
Ленивые – .+? – стараются как можно быстрее перескочить на последующую часть RegExp
/<.+?>/.exec("Some <tag>text</tag> here")
Притяжательные (Possessive quantifiers) – .++ – работает как жадный алгоритм, но не сохраняет инфо для бектрекинга.
/<.++>/.exec("Some <tag>text</tag> here") – не найдёт ничего, так как в .++ попадёт всё до конца строки и символ ">" не сможет быть найден, а поскольку информации о бектрекинге нет, то соответственно регулярка не тратит время на него и сразу фейлиться.
/<[^>]++>/.exec("Some <tag>text</tag> here") – это быстрый способ поиска (без бектрекинга) со взаимоисключающими условиями.