Регулярное выражение для сопоставления строки, содержащей подстроки, разделенные точками

#php #regex #validation

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

Вопрос:

Мне нужно получить значение из массива, используя точечную нотацию. Например:

 $arr = [
    'first' => [
        'second' => [
            'third' => 'hello'
        ]
    ]
];

$value = array_dot($arr, 'first.second.third'); // returns "hello"
 

Итак, что мне нужно сделать, это проверить, является ли это допустимой строкой, с помощью которой мы могли бы получить значение из массива.

Ограничения:

  • только символы, не содержащие пробелов
  • содержит хотя бы одну точку
  • невозможно начать или закончить точкой
  • перед и после каждой точки должна быть подстрока, не являющаяся точкой

Случаи:

 `value.inside.array` valid
`val-2.of.array` valid
`.var2.in.arr` invalid
`dot.notation.` invalid
`value. dot` invalid
`consecutive....dots` invalid
 

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

1. Должен consecutive....dots быть допустимый путь?

2. @mickmackusa нет.

Ответ №1:

Допустимый путь, насколько я понимаю, будет начинаться с одной или нескольких не-точек, затем за ним последует одна или несколько последовательностей точки, затем одна или несколько не-точек (повторяется по мере необходимости до конца строки).

Вот эта логика в шаблоне регулярных выражений.

Код: (Демо)

 $array = [
    "value.inside.array",
    "val-2.of.array",
    ".var2.in.arr",
    "dot.notation.",
    "value. dot",
    "consecutive....dots",
    "a.b.c.d.e.f"
];

var_export(
    preg_grep('~^[^.s] (?:.[^.s] ) $~', $array)
);
 

Вывод:

 array (
  0 => 'value.inside.array',
  1 => 'val-2.of.array',
  6 => 'a.b.c.d.e.f',
)
 

Или разрешить последовательные точки с этим шаблоном: (Демо)

 ~^[^.s] .S*[^.s]$~
 

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

1. избегать последовательных точек имеет смысл @mickmackusa!

2. Я не совсем уверен. Ключ массива может быть пустым. 3v4l.org/uloop Это может быть субъективным решением для ОП.

3. Я поддерживаю этот ответ, поскольку он правильно обрабатывает все крайние случаи (в отличие от принятого решения).

Ответ №2:

Попробуйте это:

 ^[^.s]S*.S*[^.s]$
 

Объяснение:

 ^[^.s]     Start with any non-dot and non-white character
S*             Any non space characters
.              Force at least one dot
S*             Any non space characters
[^.s]$    End with any non-dot and non-white character
 

Демонстрация здесь.

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

1. Сравните свой вывод с моим в этой демонстрации: 3v4l.org/hplm8

2. Я получил хорошие ответы от всех, но почему-то этот мне нравится больше всего. Ваше здоровье.

Ответ №3:

Я бы использовал preg_match_all здесь соответствующий шаблон регулярных выражений. Мы можем сначала сформировать разделенную пробелом единственную строку из всех входных терминов, используя implode() . Затем используйте регулярное выражение сопоставить все, чтобы найти совпадающие термины.

 $array = ["value.inside.array", "val-2.of.array", ".var2.in.arr", "dot.notation.", "value. dot"];
$input = implode(" ", $array);
preg_match_all("/(?<!S)[^.s]S*.S*[^.s](?!S)/", $input, $matches);
print_r($mstches[0]);
 

Это выводит:

 Array
(
    [0] => value.inside.array
    [1] => val-2.of.array
)
 

Вот объяснение шаблона регулярных выражений:

 (?<!S) assert that what precedes is either whitespace or the start of the string
[^.s]  first character is non whitespace other than dot
S*     match zero or more non whitespace characters
.      match a dot
S*     match zero or more non whitespace characters
[^.s]  final character is non whitespace other than dot
(?!S)  assert that what follows is either whitespace or the start of the string
 

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

1.Быть или не быть, вот в .... чем вопрос.

2. @mickmackusa Нет, это точечная нотация для массивов, обычно используемая в Laravel, как средство доступа к ключам внутри ассоциативного массива.

3. @Amir если ответ таков No , то два других ответа будут полезны вам не во всех случаях, и мой ответ является единственным правильным на странице, и вы приняли неправильный ответ.