Разделить слово camelCase на слова с php preg_match (регулярное выражение)
Как бы я хотел разделить слово:
oneTwoThreeFour
в массив, чтобы я мог получить:
one Two Three Four
с preg_match
?
Я устал от этого, но он просто дает целое слово
$words = preg_match("/[a-zA-Z]*(?:[a-z][a-zA-Z]*[A-Z]|[A-Z][a-zA-Z]*[a-z])[a-zA-Z]*\b/", $string, $matches)`;
Ответы
Ответ 1
Вы также можете использовать preg_match_all
как:
preg_match_all('/((?:^|[A-Z])[a-z]+)/',$str,$matches);
Пояснение:
( - Start of capturing parenthesis.
(?: - Start of non-capturing parenthesis.
^ - Start anchor.
| - Alternation.
[A-Z] - Any one capital letter.
) - End of non-capturing parenthesis.
[a-z]+ - one ore more lowercase letter.
) - End of capturing parenthesis.
Ответ 2
Вы можете использовать preg_split
как:
$arr = preg_split('/(?=[A-Z])/',$str);
Видеть это
Я в основном разделяю строку ввода перед заглавной буквой. Используемое регулярное выражение (?=[AZ])
соответствует точке непосредственно перед заглавной буквой.
Ответ 3
Я знаю, что это старый вопрос с принятым ответом, но IMHO есть лучшее решение:
<?php // test.php Rev:20140412_0800
$ccWord = 'NewNASAModule';
$re = '/(?#! splitCamelCase Rev:20140412)
# Split camelCase "words". Two global alternatives. Either g1of2:
(?<=[a-z]) # Position is after a lowercase,
(?=[A-Z]) # and before an uppercase letter.
| (?<=[A-Z]) # Or g2of2; Position is after uppercase,
(?=[A-Z][a-z]) # and before upper-then-lower case.
/x';
$a = preg_split($re, $ccWord);
$count = count($a);
for ($i = 0; $i < $count; ++$i) {
printf("Word %d of %d = \"%s\"\n",
$i + 1, $count, $a[$i]);
}
?>
Обратите внимание, что это регулярное выражение (например, решение codaddict '/(?=[A-Z])/'
, которое работает как шарм для хорошо сформированных слов camelCase), соответствует только позиции внутри строки и вообще не потребляет текст. Это решение обладает дополнительным преимуществом, что оно также корректно работает для не-правильно сформированных псевдо-верблюдных слов, таких как: StartsWithCap
и: hasConsecutiveCAPS
.
Вход:
oneTwoThreeFour
StartsWithCap
hasConsecutiveCAPS
NewNASAModule
Вывод:
Word 1 of 4 = "one"
Word 2 of 4 = "Two"
Word 3 of 4 = "Three"
Word 4 of 4 = "Four"
Word 1 of 3 = "Starts"
Word 2 of 3 = "With"
Word 3 of 3 = "Cap"
Word 1 of 3 = "has"
Word 2 of 3 = "Consecutive"
Word 3 of 3 = "CAPS"
Word 1 of 3 = "New"
Word 2 of 3 = "NASA"
Word 3 of 3 = "Module"
Отредактировано: 2014-04-12: Измененное регулярное выражение, script и тестовые данные для правильного разделения: "NewNASAModule"
case (в ответ на комментарий rr).
Ответ 4
Функциональная версия ответа @ridgerunner.
/**
* Converts camelCase string to have spaces between each.
* @param $camelCaseString
* @return string
*/
function fromCamelCase($camelCaseString) {
$re = '/(?<=[a-z])(?=[A-Z])/x';
$a = preg_split($re, $camelCaseString);
return join($a, " " );
}
Ответ 5
В то время как ответ ridgerunner работает отлично, кажется, что он не работает со всеми подстроками, которые появляются в середине предложения. Я использую следующие и, похоже, разбираюсь с ними просто:
function splitCamelCase($input)
{
return preg_split(
'/(^[^A-Z]+|[A-Z][^A-Z]+)/',
$input,
-1, /* no limit for replacement count */
PREG_SPLIT_NO_EMPTY /*don't return empty elements*/
| PREG_SPLIT_DELIM_CAPTURE /*don't strip anything from output array*/
);
}
Некоторые тестовые примеры:
assert(splitCamelCase('lowHigh') == ['low', 'High']);
assert(splitCamelCase('WarriorPrincess') == ['Warrior', 'Princess']);
assert(splitCamelCase('SupportSEELE') == ['Support', 'SEELE']);
assert(splitCamelCase('LaunchFLEIAModule') == ['Launch', 'FLEIA', 'Module']);
assert(splitCamelCase('anotherNASATrip') == ['another', 'NASA', 'Trip']);
Ответ 6
$string = preg_replace( '/([a-z0-9])([A-Z])/', "$1 $2", $string );
Трюк - это повторяемый шаблон $1 $2 $1 $2 или ниже UPPERlower UPPERlower и т.д....
например
helloWorld = $1 соответствует "привет", $2 соответствует "W" и $1 соответствует "orld", так что вы получаете $1 $2 $1 или "hello World", соответствует HelloWorld как $2 $1 $2 $1 или снова "Hello World". Затем вы можете опустить нижний регистр в верхнем регистре первым словом или взорвать их на пробел или использовать символ _ или какой-либо другой, чтобы они не разделялись.
Короткий и простой.
Ответ 7
Я взял классный код Ridgerunner (выше) и сделал его функцией:
echo deliciousCamelcase('NewNASAModule');
function deliciousCamelcase($str)
{
$formattedStr = '';
$re = '/
(?<=[a-z])
(?=[A-Z])
| (?<=[A-Z])
(?=[A-Z][a-z])
/x';
$a = preg_split($re, $str);
$formattedStr = implode(' ', $a);
return $formattedStr;
}
Это вернет: New NASA Module
Ответ 8
Другим вариантом является сопоставление /[AZ]?[az]+/
- если вы знаете, что ваш ввод в правильном формате, он должен работать хорошо.
[AZ]?
будет соответствовать заглавной букве (или ничего). [az]+
будет соответствовать всем следующим строчным буквам до следующего соответствия.
Рабочий пример: https://regex101.com/r/kNZfEI/1
Ответ 9
Возможно, мой вопрос может помочь вам,
Я спросил то же самое вчера, но о Java
Разбивка строк на символы, которые находятся в верхнем регистре
Ответ 10
Вы можете разделить на "скольжение" от нижнего регистра до верхнего регистра, таким образом:
$parts = preg_split('/([a-z]{1})[A-Z]{1}/', $string, -1, PREG_SPLIT_DELIM_CAPTURE);
//PREG_SPLIT_DELIM_CAPTURE to also return bracketed things
var_dump($parts);
Досадно, что вам придется перестроить слова из каждой соответствующей пары элементов в $parts
Надеюсь, что это поможет
Ответ 11
Прежде всего, благодарю вас за ваш образец, это очень помогло!
Мне нужно решение, которое работает в случае, если существует предлог "a":
например. thisIsACamelcaseSentence.
Я нашел решение при выполнении двухэтапного preg_match и сделал функцию с некоторыми опциями:
/*
* input: 'thisIsACamelCaseSentence' output: 'This Is A Camel Case Sentence'
* options $case: 'allUppercase'[default] >> 'This Is A Camel Case Sentence'
* 'allLowerCase' >> 'this is a camel case sentence'
* 'firstUpperCase' >> 'This is a camel case sentence'
* @return: string
*/
function camelCaseToWords($string, $case = null){
isset($case) ? $case = $case : $case = 'allUpperCase';
// Find first occurances of two capitals
preg_match_all('/((?:^|[A-Z])[A-Z]{1})/',$string, $twoCapitals);
// Split them with the 'zzzzzz' string. e.g. 'AZ' turns into 'AzzzzzzZ'
foreach($twoCapitals[0] as $match){
$firstCapital = $match[0];
$lastCapital = $match[1];
$temp = $firstCapital.'zzzzzz'.$lastCapital;
$string = str_replace($match, $temp, $string);
}
// Now split words
preg_match_all('/((?:^|[A-Z])[a-z]+)/', $string, $words);
$output = "";
$i = 0;
foreach($words[0] as $word){
switch($case){
case 'allUpperCase':
$word = ucfirst($word);
break;
case 'allLowerCase':
$word = strtolower($word);
break;
case 'firstUpperCase':
($i == 0) ? $word = ucfirst($word) : $word = strtolower($word);
break;
}
// remove te 'zzzzzz' from a word if it has
$word = str_replace('zzzzzz','', $word);
$output .= $word." ";
$i++;
}
return $output;
}
Не стесняйтесь использовать его, и в случае, если есть "более простой" способ сделать это за один шаг, прокомментируйте!
Ответ 12
Полная функция, основанная на ответе @codaddict:
function splitCamelCase($str) {
$splitCamelArray = preg_split('/(?=[A-Z])/', $str);
return ucwords(implode($splitCamelArray, ' '));
}
Ответ 13
При определении наилучшего шаблона для вашего проекта вам необходимо учитывать следующие факторы шаблона:
- Точность (робастность) - является ли модель правильной во всех случаях и является ли она обоснованной на будущее
- Эффективность - шаблон должен быть прямым, обдуманным и избегать ненужного труда
- Краткость - шаблон должен использовать соответствующие методы, чтобы избежать ненужной длины символов
- Читаемость - шаблон должен быть максимально простым
Вышеперечисленные факторы также оказываются в иерархическом порядке, который стремится подчиняться. Другими словами, для меня не имеет большого смысла расставлять приоритеты 2, 3 или 4, когда 1 не совсем удовлетворяет требованиям. Читаемость находится внизу списка для меня, потому что в большинстве случаев я могу следовать синтаксису.
Группы захвата и Lookarounds часто влияют на эффективность шаблона. Правда в том, что если вы не выполняете это регулярное выражение для тысяч входных строк, вам не нужно трудиться над эффективностью. Возможно, более важно сосредоточиться на удобочитаемости шаблона, что может быть связано с краткостью шаблона.
Некоторые шаблоны ниже потребуют некоторой дополнительной обработки /preg_
их функцией preg_
, но вот некоторые сравнения шаблонов, основанные на вводе образца OP:
Шаблоны preg_split()
:
-
/^[^AZ]+\K|[AZ][^AZ]+\K/
(21 шаг) -
/(^[^AZ]+|[AZ][^AZ]+)/
(26 шагов) -
/[^AZ]+\K(?=[AZ])/
(43 шага) -
/(?=[AZ])/
(50 шагов) -
/(?=[AZ]+)/
(50 шагов) -
/([az]{1})[AZ]{1}/
(53 шага) -
/([a-z0-9])([AZ])/
(68 шагов) -
/(?<=[az])(?=[AZ])/x
(94 шага)... для записи, x
бесполезен. -
/(?<=[az])(?=[AZ])|(?<=[AZ])(?=[AZ][az])/
(134 шага)
Шаблоны preg_match_all()
:
-
/[AZ]?[az]+/
(14 шагов) -
/((?:^|[AZ])[az]+)/
(35 шагов)
Я укажу, что есть небольшая разница между выводом preg_match_all()
и preg_split()
. preg_match_all()
выведет 2-мерный массив, другими словами, все совпадения полной строки будут находиться в подмассиве [0]
; если используется группа захвата, эти подстроки будут в подмассиве [1]
. С другой стороны, preg_split()
выводит только одномерный массив и поэтому обеспечивает менее раздутый и более прямой путь к желаемому выводу.
Некоторые шаблоны недостаточны при работе со строками camelCase, которые содержат в себе подстроку ALLCAPS/акроним. Если это ограниченный случай, который возможен в вашем проекте, логично рассматривать только шаблоны, которые правильно обрабатывают эти случаи. Я не буду тестировать строки ввода TitleCase, потому что это слишком далеко от вопроса.
Новая расширенная батарея тестовых строк:
oneTwoThreeFour
hasConsecutiveCAPS
newNASAModule
USAIsGreatAgain
Подходящие шаблоны preg_split()
:
-
/[az]+\K|(?=[AZ][az]+)/
(149 шагов) * Мне пришлось использовать [az]
для демонстрации, чтобы правильно считать -
/(?<=[az])(?=[AZ])|(?<=[AZ])(?=[AZ][az])/
(547 шагов)
Подходящий шаблон preg_match_all()
:
-
/[AZ]?[az]+|[AZ]+(?=[AZ][az]|$)/
(75 шагов)
Наконец, мои рекомендации основаны на моих шаблонных принципах/факторной иерархии. Кроме того, я рекомендую preg_split()
preg_match_all()
(несмотря на то, что шаблоны имеют меньше шагов), поскольку это напрямую связано с желаемой структурой вывода. (конечно, выбирай что хочешь)
Код: (Демо)
$noAcronyms = 'oneTwoThreeFour';
var_export(preg_split('~^[^A-Z]+\K|[A-Z][^A-Z]+\K~', $noAcronyms, 0, PREG_SPLIT_NO_EMPTY));
echo "\n---\n";
var_export(preg_match_all('~[A-Z]?[^A-Z]+~', $noAcronyms, $out) ? $out[0] : []);
Код: (Демо)
$withAcronyms = 'newNASAModule';
var_export(preg_split('~[^A-Z]+\K|(?=[A-Z][^A-Z]+)~', $withAcronyms, 0, PREG_SPLIT_NO_EMPTY));
echo "\n---\n";
var_export(preg_match_all('~[A-Z]?[^A-Z]+|[A-Z]+(?=[A-Z][^A-Z]|$)~', $withAcronyms, $out) ? $out[0] : []);