2010-10-22 4 views
27

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

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

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

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

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

+1

Что бы вы хотели сделать с помощью 'ThisIsANarrowImageOfHIV? 'Присоединиться к n или разделить ВИЧ? –

ответ

50
s = 'nowIsTheTime' 

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

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

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

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

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

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

+1

Вы пробовали 'NowIsTheTime'? – splash

+1

@splash: он по-прежнему отлично работает – ryeguy

+0

Во время моих тестов это регулярное выражение приводит к '[" "," Now "," Is "," The "," Time "]', если первая буква является заглавной буквой. Что я не так? – splash

2

Вы пробовали

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

?

2

событие, хотя это регулярное выражение вопрос рубин и answer by 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"] 
27

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

5

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

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

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

"NowIsTheTime".titleize 

Для ГорбатыйРегистр:

"nowIsTheTime".titleize.camelize :lower 
+0

Важно отметить, что '# titleize' и' # camelize' являются строго методами Rails, а не в основном Ruby. – onebree

0

Ответ от 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); 
} 
Смежные вопросы