Учитывая регулярное выражение типа /*
, которое может законно соответствовать нулевым символам, движок регулярных выражений должен убедиться, что он никогда не совпадет более одного раза в одном месте, иначе он застрянет в бесконечном цикле. Таким образом, если он потребляет ноль символов, двигатель переходит вперед на одну позицию перед попыткой другого совпадения. Насколько я знаю, это единственная ситуация, в которой движок регулярных выражений делает что-либо по собственной инициативе.
То, что вы видите, является противоположной ситуацией: регулярное выражение потребляет один или несколько символов, затем на следующем раунде оно пытается начать сопоставление в том месте, где оно остановилось. Не берите в голову, что это регулярное выражение не может соответствовать ничему, кроме одного символа, и оно уже соответствует такому числу, как могло; у него все еще есть возможность ничего не сопоставлять, так что это то, что он делает.
Итак, почему ваше регулярное выражение не совпадает дважды в начале, как это происходит в конце? Из-за начального якоря (^
). Если субъект начинает с одного или нескольких слешей, он их потребляет, а затем пытается сопоставить ноль слешей, но это не удается, потому что он больше не находится в начале строки. И если в начале нет косых черт, то ручной сдвиг имеет тот же эффект.
На конце субъекта это другая история. Если там нет косых черт, это ничего не соответствует, пытается столкнуться и терпит неудачу; конец истории. Но если он действительно соответствует одному или нескольким слэшам, он использует их и пытается сопоставить снова - и успешно, потому что якорь $
все еще совпадает.
Таким образом, в общем, если вы хотите предотвратить такое двойное совпадение, вы можете добавить условие к началу совпадения, чтобы предотвратить его, как якорь ^
для первого альтернатива:
preg_replace('%^/*|(?<!/)/*$%', '/', $d);
... или убедитесь, что часть регулярного выражения должна содержать хотя бы один символ:
preg_replace('%^/*|([^/])/*$%', '$1/', $d);
Но в этом случае у вас есть гораздо более простой вариант, как продемонстрировал Джон Кугельман: просто захватите часть, которую вы хотите сохранить, и бросьте оставшуюся часть.