Подтвердить что ты не робот

Как разбить строку CamelCase в подстроках в Ruby?

У меня есть хорошая строка CamelCase, такая как ImageWideNice или ImageNarrowUgly. Теперь я хочу разбить эту строку в своих подстроках, например Image, Wide или Narrow, и Nice или Ugly.

Я думал, что это можно решить просто

camelCaseString =~ /(Image)((Wide)|(Narrow))((Nice)|(Ugly))/

Но как ни странно, это заполняет только $1 и $2, но не $3.

У вас есть лучшая идея для разделения этой строки?

4b9b3361

Ответ 1

s = 'nowIsTheTime'

s.split /(?=[A-Z])/

=> ["now", "Is", "The", "Time"]

?=pattern - пример положительного обзора. Он по существу соответствует точке в строке прямо перед шаблоном. Он не использует символы, т.е. Не включает в себя шаблон как часть совпадения. Другой пример:

    irb> 'streets'.sub /t(?=s)/, '-'
=> "stree-s"

В этом случае соответствует s (соответствует только второй t), но не заменяется. Благодаря @Bryce и его ссылка regexp doc. Брайс Андерсон добавляет объяснение:

?= в начале группы соответствия () называется положительным lookahead, что является просто способом сказать, что в то время как регулярное выражение глядя на символы при определении того, соответствует ли он, это не что делает их частью матча. split() обычно ест промежуточный символов, но в этом случае сам матч пуст, поэтому есть ничего [там].

Ответ 2

Я знаю, что это старо, но стоит упомянуть других, которые могли бы это искать. В рельсах вы можете сделать это: "NowIsTheTime".underscore.humanize

Ответ 3

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

Если вы знаете, какая из этих форм находится в строке, или вы хотите принудительно ее или нет, Inflector может это сделать.

Для случая Паскаля:

"NowIsTheTime".titleize

Для случая верблюда:

"nowIsTheTime".titleize.camelize :lower

Ответ 4

Вы пробовали

camelCaseString =~ /(Image)(Wide|Narrow)(Nice|Ugly)/

?

Ответ 5

Событие, хотя это вопрос с регулярным выражением Ruby и ответ от DigitalRoss правильный и сияет своей простотой, я хочу добавить ответ Java:

// this regex doesn't work perfect with Java and other regex engines
"NowIsTheTime".split("(?=[A-Z])"); // ["", "Now", "Is", "The", "Time"]

// this regex works with first uppercase or lowercase characters
"NowIsTheTime".split("(?!(^|[a-z]|$))"); // ["Now", "Is", "The", "Time"]
"nowIsTheTime".split("(?!(^|[a-z]|$))"); // ["now", "Is", "The", "Time"]

Ответ 6

Ответ DigitalRoss не будет распознавать акронимы, встроенные в CamelCase. Например, он разделит "MyHTMLTricks" на "My H T M L Tricks" вместо "My HTML Tricks".

Вот еще один вариант, основанный на функции AsSpaced() в PmWiki, который отлично справляется с такими случаями, как это:

"MyHTMLTricks" \
.gsub(/([[:lower:]\\d])([[:upper:]])/, '\1 \2') \
.gsub(/([^-\\d])(\\d[-\\d]*( |$))/,'\1 \2') \
.gsub(/([[:upper:]])([[:upper:]][[:lower:]\\d])/, '\1 \2')

=> "My HTML Tricks"

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

"MyHTMLTricks" \
.gsub(/([[:lower:]\\d])([[:upper:]])/, '\1 \2') \
.gsub(/([^-\\d])(\\d[-\\d]*( |$))/,'\1 \2') \
.gsub(/([[:upper:]])([[:upper:]][[:lower:]\\d])/, '\1 \2') \
.split

=> ["My", "HTML", "Tricks"]

Для записи здесь находится исходный код PHP из PmWiki.

function AsSpaced($text) {
    $text = preg_replace("/([[:lower:]\\d])([[:upper:]])/", '$1 $2', $text);
    $text = preg_replace('/([^-\\d])(\\d[-\\d]*( |$))/', '$1 $2', $text);
    return preg_replace("/([[:upper:]])([[:upper:]][[:lower:]\\d])/", '$1 $2', $text);
}