соответствие строки php подстановочному знаку *?

#php #regex #string-matching

#php #регулярное выражение #сопоставление строк

Вопрос:

Я хочу предоставить возможность сопоставлять строку с подстановочным знаком * .

Пример

 $mystring = 'dir/folder1/file';
$pattern = 'dir/*/file';

stringMatchWithWildcard($mystring,$pattern);  //> Returns true
  

Пример 2:

 $mystring = 'string bl#abla;y';
$pattern = 'string*y'; 

stringMatchWithWildcard($mystring,$pattern);  //> Returns true
  

Я подумал что-то вроде:

 function stringMatch($source,$pattern) {
    $pattern = preg_quote($pattern,'/');        
    $pattern = str_replace( '*' , '.*?', $pattern);   //> This is the important replace
    return (bool)preg_match( '/^' . $pattern . '$/i' , $source );
}
  

В основном замена * на .*? (учитывая, что в *nix среде * соответствует empty строке) ©vbence

Какие-либо улучшения / предложения?

// Добавлено return (bool) , потому что preg_match возвращает int

Ответ №1:

preg_match Здесь нет необходимости. В PHP есть функция сравнения подстановочных знаков, специально созданная для таких случаев:

fnmatch()

И fnmatch('dir/*/file', 'dir/folder1/file') , вероятно, уже сработало бы для вас. Но будьте осторожны, что * подстановочный знак также добавит дополнительные косые черты, как это сделал бы preg_match .

Комментарии:

1. привет, Марио. в fnmatches есть еще какая-то функция, подобная [] . Мне просто нужно * как «специальный символ»

2. fnmatch не поддерживается в системах, отличных от POSIX. (Я вижу, что php5.3 теперь также поддерживает Windows). Так что это не всегда лучший способ

Ответ №2:

Вместо этого вы должны просто использовать .* .

 $pattern = str_replace( '*' , '.*', $pattern);   //> This is the important replace
  

Редактировать: Также ваши ^ и $ были в неправильном порядке.

 <?php

function stringMatchWithWildcard($source,$pattern) {
    $pattern = preg_quote($pattern,'/');        
    $pattern = str_replace( '*' , '.*', $pattern);   
    return preg_match( '/^' . $pattern . '$/i' , $source );
}

$mystring = 'dir/folder1/file';
$pattern = 'dir/*/file';

echo stringMatchWithWildcard($mystring,$pattern); 



$mystring = 'string bl#abla;y';
$pattern = 'string*y'; 

echo stringMatchWithWildcard($mystring,$pattern); 
  

Рабочая демонстрация: http://www.ideone.com/mGqp2

Комментарии:

1. Я не знаю, хочу ли я предоставить возможность сопоставлять это 'dir//file' с 'dir/*/file'

2. .* является жадным, оно съест всю оставшуюся часть вашей строки, а не только минимальное количество символов для продолжения шаблонов. Так что, если у вас есть что-нибудь после .* , результат всегда будет false.

3. Я думал, что это именно то, что вы хотели сделать с . ? из вашего описания.

4. @vbence preg_match('/.*a/', 'aa') ?

5. Хорошо, похоже, match это даст те же результаты.

Ответ №3:

 . ?
  

Вызывает не жадное сопоставление для всех символов. Это НЕ равно «*», потому что оно не будет соответствовать пустой строке.

Следующий шаблон также будет соответствовать пустой строке:

 .*?
  

итак…

 stringMatchWithWildcard ("hello", "hel*lo"); // will give true
  

Комментарии:

1. как вы думаете, я должен разрешить пустую строку? Также рассмотрим dir: 'dir//file' соответствие 'dir/*/file' ?

2. Если вы хотите, чтобы это работало аналогично тому, как работают оболочки операционной системы, тогда вы должны разрешить пустую строку. Просто попробуйте, echo > hello за которым dir hello* следует в Windows или ls hello* в * nix. В этом контексте * соответствует пустой строке.

3. Было бы вежливо дать комментарий с вашим -1.

4. ах, здорово! спасибо за сравнение * nix! (также я не получил -1 вашего ответа, у меня нет причин это делать)

5. @yes123 Да, я знаю, не обвиняю. 🙂

Ответ №4:

Вы путаете окончание ( $ ) и начало ( ^ ). Это:

 preg_match( '/$' . $pattern . '^/i' , $source );
  

Должно быть:

 preg_match( '/^' . $pattern . '$/i' , $source );
  

Ответ №5:

Единственная проблема, с которой вы столкнетесь, заключается в том, что вызов preg_quote() будет экранировать символ звездочки. Учитывая это, ваш str_replace() заменит * , но не escape-символ перед ним.

Поэтому вам следует изменить str_replace('*' ..) на str_replace('*'..)

Комментарии:

1. я пропустил это из документа, к сожалению. исправлено

Ответ №6:

 $pattern = str_replace( '*' , '. ?', $pattern);   // at least one character
  

Комментарии:

1. Пожалуйста, добавьте некоторые пояснения к вашему коду — взгляните на другие ответы на этот вопрос для некоторого вдохновения