Как я могу преобразовать строку из верблюжьего ящика в змеиный и обратно на идиоматическом котлине?
Ищем код, который будет выполнять такие преобразования: "MyCamelCaseA" в "my_camel_case_a", "AMultiWordString" в "a_multi_word_string", "my_camel_case_a" в "myCamelCaseA" или "MyCamelCaseA", "a_multi_word_String" в "a_multi_word_string" в "a_multi_word_string"
7 ответов
Вот расширения класса String, которые используют регулярное выражение и замены для преобразования строки из случая верблюда в случай змеи и из случая змеи в случай верблюда:
val camelRegex = "(?<=[a-zA-Z])[A-Z]".toRegex()
val snakeRegex = "_[a-zA-Z]".toRegex()
// String extensions
fun String.camelToSnakeCase(): String {
return camelRegex.replace(this) {
"_${it.value}"
}.toLowerCase()
}
fun String.snakeToLowerCamelCase(): String {
return snakeRegex.replace(this) {
it.value.replace("_","")
.toUpperCase()
}
}
fun String.snakeToUpperCamelCase(): String {
return this.snakeToLowerCamelCase().capitalize()
}
Вот примеры использования расширения String:
print("${"MyCamelCaseA".camelToSnakeCase()}\n")
my_camel_case_a
print("${"AMultiWordString".camelToSnakeCase()}\n")
a_multi_word_string
"my_camel_case_a".snakeToLowerCamelCase()
myCamelCaseA
"my_camel_case_a".snakeToUpperCamelCase()
MyCamelCaseA
Я бы пошел с этими реализациями:
fun String.toCamelCase() =
split('_').joinToString("", transform = String::capitalize)
... который разбивает строку, используя змей в качестве разделителей, а затем повторно прикрепляет части как заглавные слова без разделителя.
fun String.toSnakeCase() = replace(humps, "_").toLowerCase()
private val humps = "(?<=.)(?=\\p{Upper})".toRegex()
... который использует регулярное выражение для поиска позиций перед горбами, вставляя змеи, а затем преобразует всю строку в нижний регистр. Регулярное выражение состоит из двух частей, первая
(?<=.)
- это положительный взгляд назад, говорящий, что ему должен предшествовать символ, а вторая часть
(?=\\p{Upper})
использует положительный просмотр вперед, говоря, что за ним должен следовать символ верхнего регистра.
Вот мой удар по этому поводу.
fun String.camelToSnakeCase() = fold(StringBuilder(length)) { acc, c ->
if (c in 'A'..'Z') (if (acc.isNotEmpty()) acc.append('_') else acc).append(c + ('a' - 'A'))
else acc.append(c)
}.toString()
Мой подход также написан в форме функции расширения, но в нем не используются регулярные выражения, вместо этого он идет посимвольно, обрабатывая их и складывая результат обработки в аккумулятор, который вначале является пустым. StringBuilder
. Обработка выглядит следующим образом:
- если символ не является заглавной латинской буквой, добавить его в аккумулятор как есть
- если символ - латинская буква в верхнем регистре, то также проверьте, не является ли это первым символом строки (аккумулятор не пуст). Если это не так, добавьте знак подчеркивания в аккумулятор. Наконец, добавьте символы нижнего регистра.
Следует отметить, что kotlin.text.StringBuilder
используется, а не JDK.
Если у вас есть jackson-databind в пути к классам, вы можете использовать следующую служебную функцию:
import com.fasterxml.jackson.databind.PropertyNamingStrategies
fun String.toSnakeCase(): String =
PropertyNamingStrategies.SnakeCaseStrategy().translate(this)
fun main() {
// should output this_is_the_case
println("thisIsTheCase".toSnakeCase())
}
это моя попытка только с котлином
val camelCaseString = "thisIsCamelCase"
val snakeCaseString = camelCaseString.map {
if (it.isUpperCase()){
"_${it.toLowerCase()}"
}else
{"$it"}
}
.joinToString(separator = "")
System.out.println("here is your snake string: $snake_case_string")
вот ваша змеиная строка: this_is_camel_case
преобразовать змею в верблюда
val snakeCaseString = "snake_case_string"
val camelCase = StringBuilder()
var prevChar = '$'
snakeCaseString.forEach {
if(prevChar.equals('_')){
camelCase.append(it.toUpperCase())
}else if(!it.equals('_')){
camelCase.append(it)
}
prevChar = it
}
System.out.println(camelCase.toString())
snakeCaseString
Я взял один из ответов здесь, добавил заголовок и немного изменил API.
val camelRegex = "(?<=[a-zA-Z])[A-Z]".toRegex()
val snakeRegex = "_[a-zA-Z]".toRegex()
@JvmInline
value class SnakeCaseString(private val string: String) {
fun toCamelCase(): String = snakeRegex.replace(string) { it.value.replace("_", "").uppercase() }
fun toUpperCamelCase(): String =
toCamelCase().replaceFirstChar { if (it.isLowerCase()) it.titlecase() else it.toString() }
fun toTitleCase(): String = snakeRegex.replace(string) { it.value.replace("_", " ").uppercase() }
.replaceFirstChar { if (it.isLowerCase()) it.titlecase() else it.toString() }
}
@JvmInline
value class CamelCaseString(private val string: String) {
fun toSnakeCase(): String = camelRegex.replace(string) { "_${it.value}" }.lowercase()
fun toTitleCase(): String = camelRegex.replace(string) { "_${it.value}" }
.replaceFirstChar { if (it.isLowerCase()) it.titlecase() else it.toString() }
}
fun String.asSnakeCase() = SnakeCaseString(this)
fun String.asCamelCase() = CamelCaseString(this)
Если вам нужен метод с вводом и выводом, вот как я это сделал:
private fun convertCamelToSnakeCase(camelCase : String) : String {
val snakeCase = StringBuilder()
for(character in camelCase) {
if(character.isUpperCase()) {
snakeCase.append("_${character.toLowerCase()}")
} else {
snakeCase.append(character)
}
}
return snakeCase.removePrefix("_").toString()
}