У меня есть класс с интервалом между именами..
"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
.