Как разбить строку CamelCase на ее подстроки в Ruby? - PullRequest
29 голосов
/ 22 октября 2010

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

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

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

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

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

Ответы [ 7 ]

55 голосов
/ 22 октября 2010
s = 'nowIsTheTime'

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

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

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

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

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

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

30 голосов
/ 16 ноября 2011

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

8 голосов
/ 31 августа 2014

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

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

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

"NowIsTheTime".titleize

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

"nowIsTheTime".titleize.camelize :lower
2 голосов
/ 22 октября 2010

Событие, хотя это вопрос Ruby regex и ответ от 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"]
2 голосов
/ 22 октября 2010

Вы пробовали

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

?

1 голос
/ 29 декабря 2017

Ответ от DigitalRoss не распознает аббревиатуры, встроенные в CamelCase.Например, он разделит «MyHTMLTricks» на «My HTML 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);
}
0 голосов
/ 19 сентября 2018
I/p:- "ImageWideNice".scan(/[A-Z][a-z]+/).join(",")

O/p:- "Image,Wide,Nice"
...