Так что я застрял — я просмотрел здесь множество ответов, но, похоже, ни один из них не решил мою последнюю проблему.
Через 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 ().
Но, как писал Флай в комментариях к своему ответу, потенциально может быть много случаев, не охваченных его регулярным выражением, и ответ может быть невозможным — я не знаю, может ли это быть проблемой для регулярного выражения.
Возможно, добавив некоторое правило «Если после верхнего регистра нет строчных букв, не должно быть вставлено пробел»
Вот шаблон одиночного вызова, который не использует привязки, группы захвата или ссылки в строке замены: /(?:[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
в соответствии с просьбой ОП.
* Примечание. Точность шаблона может быть улучшена при увеличении количества образцов строк.
Вот как это можно решить:
$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.
ОБНОВЛЕНИЕ: добавлен пример для дополнительного вопроса