Два тире в регулярном выражении

160
30 декабря 2017, 04:36

Добрый день, люди добрые. В регулярных выражениях недавно, мучает одна строка... ну ни как не поддаётся.

preg_match("/^([A-z_0-9\$\s\-]+)(|\-([a-z24]+))$/i", $urlprop['func'], $urllogin22);

Вот собственно строка регулярки.

В urlprop хранится строка урл, в которой может быть 2 положения:

  • названиеТовара
  • названиеТовара-Опция

Проблема кроется в том что название товара может содержать тире "-" и регулярка уже не разбивает урл на "названиеТовара" и "Опция".

Подскажите что в моём выражении не так и как это можно было бы исправить?

Answer 1

Думаю изначально проблема не в регулярном выражении, а в логике, приведу пример для наглядности: Есть вот такие URL:

Товар-Опция
Товар-товар-Опция
Товар-товар-товар-Опция

И с помощью Look ahead мы делим строку по последнему знаку -:

preg_match("/^(.*)(?=-)[-*](.*)$/i", $urlprop['func'], $urllogin22);
var_dump($urllogin22);
array(3) {
  [0]=>
  string(12) "Товар-Опция"
  [1]=>
  string(5) "Товар"
  [2]=>
  string(6) "Опция"
}

Во всех 3х вариантах отработает всё как нужно, но если будет товар который без категории:

Товар-товар

И товар с категорией с первого примера:

Товар-Опция

Для регулярки это тоже самое, вам нужно менять структуру url чтобы понимать точно где товар где опция.

Answer 2

За самый рабочий ответ спасибо Nik'у

$opt = str_replace('-','',substr($urlprop['func'], strrpos($urlprop['func'], '-')));
$options = array('option1','option2','option3','option4');
if(in_array($opt,$options)){
    // если есть опция
}else{
    // если последнее слово после тире не подходит ни под одну из опций
}

как оказалось проще решить эту проблему вообще без регулярного выражения =)

Answer 3

Если строка имеет формат "Название-товара-Опция", то в имя товара будет сохранена часть "Название-товара", а в опцию "Опция".

Если опция не указана, то в имени товара будет строка "Название-товара"

$str = 'НазваниеТовара-Опция';
$option = '';
preg_match_all('~\w+-?\w+~u', $str, $a);
count($a[0]) > 1 ? list($name, $option) = $a[0] : $name = $a[0];
var_dump($name, $option);

UPD: Если опции заранее известны, тогда можно обойтись без регулярных выражений:

$url = 'НазваниеТовара-option1';
$temp = explode('-', $url);
$option = array_pop($temp);
$options = ['option1', 'option2', 'option3', 'option4'];
if (($k = array_search($option, $options)) !== false) {
    echo 'Товар: '. join($temp) . '<br>Опции: ' . $options[$k];
}
Answer 4

Можно воспользоваться preg_split c Negative Lookahead, который найдет последний дефис в строке

list($name, $option) = preg_split('/\-(?!.*\-)/', 'Название-товара-Опция');
echo $name.'<>',$option; // Название-товара<>Опция
READ ALSO
Двойной static_cast через void*, вместо reinterpret_cast

Двойной static_cast через void*, вместо reinterpret_cast

Некоторые авторы используют двойное преобразование через void* с помощью static_cast, вида:

223
C++: enable_shared_from_this и деструктор

C++: enable_shared_from_this и деструктор

Насколько я понимаю, в enable_shared_from_this определен свой деструкторКак мне написать свой деструктор, в котором нужно закрыть файловый дескриптор,...

230
Подсчет слов, букв в файле

Подсчет слов, букв в файле

Задача такая: подсчитать количество переменных в файлеТ

231
Помогите перевести выражение на язык С++ [требует правки]

Помогите перевести выражение на язык С++ [требует правки]

Нужно перевести это выражение на С++

262