regex — форматирование верблюжьего дела в PHP для чтения, пропуская сокращения

Так что я застрял — я просмотрел здесь множество ответов, но, похоже, ни один из них не решил мою последнюю проблему.

Через API с JSON я получаю список оборудования в формате Camelcase. Я не могу изменить это.

Мне нужно, чтобы этот верблюд был переведен на нормальный язык —

До сих пор я получил большинство слов, разделенных через:

$string = "SomeEquipmentHere";

$spaced = preg_replace('/([A-Z])/', ' $1', $string);
var_dump($spaced);

string ' Some Equipment Here' (length=20)

$trimmed = trim($spaced);
var_dump($trimmed);
string 'Some Equipment Here' (length=19)

Который работает нормально — но в некоторых оборудованиях состоит из сокращений

«ABSBrakes» — для этого потребуется ABS и отдельно от тормозов

Я не могу проверить наличие нескольких заглавных букв рядом друг с другом, потому что тогда они будут объединять АБС и тормоза — их больше, например: «CDRadio»

Итак, что нужно, так это вывод:

"ABS Brakes"

Есть ли способ отформатировать его так, если рядом с каждым есть заглавные буквы, а затем добавить только пробел перед последней заглавной буквой этой последовательности?

Я не силен в регулярных выражениях.

РЕДАКТИРОВАТЬ

Оба материала потрясающие — люди, приходящие сюда позже, должны прочитать оба ответа.

Последняя проблема состоит в следующем:

«СервисОК» становится «Сервис О К»

«ESP» становится «ES P»

Шаблон, состоящий только из чисто прописных сокращений, фиксируется функцией подсчета строчных букв, если ее нет, она пропускает preg_replace ().

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

Возможно, добавив некоторое правило «Если после верхнего регистра нет строчных букв, не должно быть вставлено пробел»

9

Решение

Вот шаблон одиночного вызова, который не использует привязки, группы захвата или ссылки в строке замены: /(?:[a-z]|[A-Z]+)\K(?=[A-Z]|\d+)/

Шаблон&Заменить демо

Код: (демонстрация)

$tests = [
'SomeEquipmentHere',
'ABSBrakes',
'CDRadio',
'Valve14',
];
foreach ($tests as $test) {
echo preg_replace('/(?:[a-z]|[A-Z]+)\K(?=[A-Z]|\d+)/',' ',$test),"\n";
}

Выход:

Some Equipment Here
ABS Brakes
CD Radio
Valve 14

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

Шаблон Объяснение:

/         #start the pattern
(?:[a-z]  #match 1 lowercase letter
|         #or
[A-Z]+)   #1 or more uppercase letters
\K        #restart the fullstring match (forget the past)
(?=[A-Z]  #look-ahead for 1 uppercase letter
|         #or
\d+)      #1 or more digits
/         #end the pattern

Редактировать:

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

/(?:[a-z]|\B[A-Z]+)\K(?=[A-Z]\B|\d+)/

Конечно, вышеприведенный шаблон не будет правильно обрабатывать ServiceOK

Демо-ссылка Слово Границы Ссылка


или этот шаблон с якорем:

/(?!^)(?=[A-Z][a-z]+|(?<=\D)\d)/

Приведенный выше шаблон будет точно разделен: SomeEquipmentHere, ABSBrakes, CDRadio, Valve14, ServiceOK, ESP в соответствии с просьбой ОП.

Демо-ссылка

* Примечание. Точность шаблона может быть улучшена при увеличении количества образцов строк.

2

Другие решения

Вот как это можно решить:

$tests = [
'SomeEquipmentHere',
'ABSBrakes',
'CDRadio',
'Valve14',
];
foreach ($tests as $test) {
echo trim(preg_replace('/\s+/', ' ', preg_replace('/([A-Z][a-z]+)|([A-Z]+(?=[A-Z]))|(\d+)/', '$1 $2 $3', $test)));
echo "\n";
}

Связанный тест на regex101.

ОБНОВЛЕНИЕ: добавлен пример для дополнительного вопроса

3

По вопросам рекламы ammmcru@yandex.ru
Adblock
detector