У меня есть класс с интервалом между именами..
"CommonCar::RedTrunk"
Мне нужно преобразовать его в строку с подчеркиванием "common_car_red_trunk", но когда я использую
"CommonCar::RedTrunk".underscore, вместо этого я получаю "common_car/red_trunk".
Есть ли другой способ выполнить то, что мне нужно?
@CarySwoveland, аминь, брат. :-)





"CommonCar::RedTrunk".gsub(':', '').underscore
или:
"CommonCar::RedTrunk".sub('::', '').underscore
или:
"CommonCar::RedTrunk".tr(':', '').underscore
Или переверните любой из них и сделайте сначала underscore(), а затем любой метод, который вы хотите использовать, чтобы заменить «/» на «_».
Хотя все эти методы выглядят в основном одинаково, есть небольшие различия, которые могут быть очень важными.
Суммируя:
gsub() — использует регулярное выражение для сопоставления с образцом, поэтому он находит любое вхождение ":" и заменяет его на "".
sub() – использует регулярное выражение для сопоставления с образцом, аналогично gsub(), за исключением того, что оно находит только первое вхождение ("g" в gsub() означает "глобальный"). Вот почему при использовании этого метода необходимо было использовать "::", иначе остался бы один ":". Имейте в виду, что этот метод будет работать только с пространством имен с одним вложением. Значение "CommonCar::RedTrunk::BigWheels" было бы преобразовано в "CommonCarRedTrunk::BigWheels".
tr() — использует строковые параметры как массивы замен одного символа. В этом случае, поскольку мы заменяем только один символ, он будет работать так же, как gsub(). Однако, если вы хотите заменить «on» на «EX», например, gsub("on", "EX") выдаст "CommEXCar::RedTrunk", а tr("on", "EX") выдаст "CEmmEXCar::RedTruXk".
https://apidock.com/ruby/String/gsub
Это решение на чистом Ruby.
r = /(?<=[a-z])(?=[A-Z])|::/
"CommonCar::RedTrunk".gsub(r, '_').downcase
#=> "common_car_red_trunk"
См. (первая форма) String#gsub и String#downcase.
Регулярное выражение можно сделать самодокументируемым, написав его в режиме свободного пробела:
r = /
(?<=[a-z]) # assert that the previous character is lower-case
(?=[A-Z]) # assert that the following character is upper-case
| # or
:: # match '::'
/x # free-spacing regex definition mode
(?<=[a-z]) — положительный взгляд назад; (?=[A-Z]) — позитивный прогноз.
Обратите внимание, что /(?<=[a-z])(?=[A-Z])/ соответствует пустой строке ("нулевой ширины"). r соответствует, например, пустой строке между 'Common' и 'Car', потому что ей предшествует строчная буква, а за ней следует прописная.
Я не знаю Rails, но думаю, вы могли бы написать
"CommonCar::RedTrunk".delete(':').underscore
Не будучи членом сообщества Rails, я бы подумал, что
to_snake_caseбудет более информативным именем, чемunderscore.