Как я могу преобразовать строку из верблюжьего ящика в змеиный и обратно на идиоматическом котлине?

Ищем код, который будет выполнять такие преобразования: "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()
}
Другие вопросы по тегам