Почему ^ * $ соответствует "127.0.0.1" - PullRequest
9 голосов
/ 21 октября 2008

Не понимаю, почему появляется следующее регулярное выражение:

^*$

Соответствует строке "127.0.0.1"? Использование Regex.IsMatch("127.0.0.1", "^*$");

При использовании Expresso он не совпадает, чего я и ожидал. Использование выражения ^.*$ соответствует строке, которую я также ожидал бы.

Технически, ^*$ должен соответствовать началу строки / строки любое количество раз, за ​​которым следует конец строки / строки. Кажется * неявно трактуется как .*

Чего мне не хватает?

EDIT: Выполните следующую команду, чтобы увидеть пример проблемы.

using System;
using System.Text.RegularExpressions;

namespace RegexFubar
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine(Regex.IsMatch("127.0.0.1", "^*$"));
            Console.Read();
        }
    }
}

Я не хочу, чтобы ^ * $ соответствовал моей строке, мне интересно, почему она соответствует . Я думаю, что выражение должно приводить к исключению или, по крайней мере, к несовпадению.

EDIT2: Чтобы устранить любую путаницу. Я не писал это регулярное выражение с намерением, чтобы оно соответствовало "127.0.0.1". Пользователь нашего приложения ввел выражение и задумался, почему оно соответствует строке, когда не должно. Посмотрев на него, я не смог придумать объяснения, почему он совпадает, особенно если учесть, что Expresso и .NET, похоже, обрабатывают его по-разному.

Я полагаю, что на этот вопрос отвечает тот факт, что реализация .NET не выдает исключение, даже если это технически неправильное выражение. Но действительно ли это то, что мы хотим?

Ответы [ 7 ]

27 голосов
/ 21 октября 2008

Ну, теоретически вы правы, это не должно совпадать. Но это зависит от того, как реализация работает внутри. Большинство регулярных выражений возьмем ваше регулярное выражение и удалим ^ с фронта (принимая во внимание, что оно должно совпадать с начала строки) и убрав $ с конца (отметив, что оно должно совпадать с концом строки), осталось только "* "и" * "само по себе является действительным регулярным выражением. Реализация, которую вы используете, просто неверна в отношении того, как с ней справиться. Вы можете попробовать, что произойдет, если вы замените «^ * $» просто на «*»; Я думаю, это также будет соответствовать всем. Похоже, что реализация обрабатывает одну звездочку как ". *".

В соответствии со стандартом ISO / IEC 9945-2: 1993, который также описан в стандарте POSIX , он нарушен. Он нарушен, потому что стандарт гласит, что после символа ^ звездочка вообще не имеет никакого особого значения. Это означает, что «^ * $» должен фактически соответствовать только одной строке, и эта строка будет "*" !

Чтобы процитировать стандарт:

Звездочка специальная, кроме случаев, когда она используется:

  • в выражении в скобках
  • как первый символ всего BRE (после начального ^, если есть)
  • как первый символ подвыражения (после начального ^, если есть); см. BRE, соответствующие нескольким символам.

Так что, если это первый символ (и ^ не считается первым символом, если присутствует), он не имеет особого значения. Это означает, что в этом случае звездочка должна соответствовать только одному символу, и это звездочка.


Обновление

Microsoft говорит

Microsoft .NET Framework обычный выражения включают в себя наиболее популярные особенности других регулярных реализации выражений, таких как те, в Perl и awk. Предназначен для совместим с Perl 5 регулярно выражения .NET Framework регулярные выражения включают функции еще видел в других реализациях, таких как сопоставление справа налево и на лету сборник.

Источник: http://msdn.microsoft.com/en-us/library/hs600312.aspx

Хорошо, давайте проверим это:

# echo -n 127.0.0.1 | perl -n -e 'print (($_ =~ m/(^.*$)/)[0]),"\n";'
-> 127.0.0.1
# echo -n 127.0.0.1 | perl -n -e 'print (($_ =~ m/(^*$)/)[0]),"\n";'
->

Нет, это не так. Perl работает правильно. ^. * $ соответствует строке, ^ * $ not => Реализация регулярного выражения в .NET не работает и не работает как Perl 5, как утверждает MS.

9 голосов
/ 21 октября 2008

Звездочка (*) соответствует предыдущему элементу НОЛЬ ИЛИ БОЛЬШЕ раз. Если вы хотите один или несколько, используйте оператор + вместо *.

Вы просите, чтобы он соответствовал необязательному началу маркера строки и концу маркера строки. То есть если мы опускаем маркер начала строки, вы ищете только маркер конца строки ... который будет соответствовать любой строке!

Я не очень понимаю, что вы пытаетесь сделать. Если бы вы могли дать нам больше информации, то, возможно, я мог бы рассказать вам, что вы должны были сделать:)

2 голосов
/ 21 октября 2008

Если вы попробуете

Regex.Match("127.0.0.1", "^*1$")

Вы увидите, что это также совпадает. Свойство Match.Index имеет значение 8, что означает, что оно соответствует последнему 1, а не первому. Это имеет смысл, потому что «^ *» будет соответствовать нулю или большему количеству начала строк, и перед «1» будет нулевое начало строки.

Подумайте, как будет соответствовать «a * 1 $», потому что перед «1 $» нет «a». Так что «* *» будет соответствовать концу строки, как ваш пример.

Кстати, в документах MSDN никогда не упоминается "*", просто "*", за исключением случаев, когда они экранируются как \ * И «*» само по себе выдаст исключение, а не совпадет с «*».

0 голосов
/ 21 октября 2008

Стандарт регулярных выражений POSIX действительно старый и ограниченный. Несколько инструментов, которые до сих пор следуют этому, такие как grep, sed и friends, в основном работают на оболочке unix / linux. Perl и PCRE - это два значительно расширенных варианта, в которых почти ничего не упомянуто в стандарте POSIX.

http://www.regular -expressions.info / refflavors.html

В PCRE и Perl движок обрабатывает ^ и $ как токены, которые соответствуют началу и концу строки (или строки, если установлен многострочный флаг). * просто повторяет маркер ^ ноль или более раз (в данном случае ровно ноль раз). Таким образом, движок ищет только конец исходной строки, который соответствует любой строке.

0 голосов
/ 21 октября 2008

Недопустимое регулярное выражение, скорее всего, то, что вы хотите написать, скорее всего, не так.

Вы пишете: «^ * $ должен совпадать с началом строки / строки любое количество раз, за ​​которым следует конец строки / строки», что подразумевает, что вы хотите многострочные регулярные выражения, но забыли, что строка не может начинаться дважды, без конца строки между ними.

Кроме того, то, что вы спрашиваете в своих требованиях, в действительности соответствует "127.0.0.1" :) "^" - это не перевод строки / возврат каретки, но также начало строки, а "$" это не просто перевод строки, но конец строки.

Кроме того, "*" соответствует как можно большему количеству (кроме случаев, когда установлен режим разжевывания), что означает, что regexp /^.**$/ regexp будет соответствовать всему. Если вы хотите управлять символами новой строки, вы должны явно их кодировать.

Надеюсь, это прояснит что-то:)

0 голосов
/ 21 октября 2008

Вы фактически говорите «соответствует строке, которая ничего или ничего не содержит». Так что это будет соответствовать. Привязки ^ и $ на самом деле не имеют значения в этом случае.

0 голосов
/ 21 октября 2008

Используя RegexDesigner , я вижу, что он совпадает на нулевом токене после 127.0.0.1. Похоже, что из-за того, что вы не указали токен и плюс соответствует нулю или более раз, он совпадает с нулем.

Должно работать следующее регулярное выражение:

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