Как я могу получить информацию txt по строкам и разделить каждую строку на отдельные классы

У меня есть текстовый файл с тремя строками кода, и мне нужно взять каждую строку и разделить ее на , чтобы я мог взять части из каждой строки и поместить их в класс. У меня будет один класс для каждой строки.

Это то, что я придумал, софер. Я просто думаю, что это слишком много кода, и хотел бы найти простой способ сделать это.

Текстовый файл выглядит так

character, stats, stats, stats
weapon, stats
armor, stats

мой код для первой строки выглядит так

class CharacterFight(
       var name : String,
       var race : String,
       var hitpoints :Int,
       var strength : Int,
       var agility : Int,

){
override fun toString(): String {
       return """Character
           Name: ${name}
           Race: ${race}
           Hitpoints :${hitpoints}
           Strength: ${strength}
           Agility: ${agility}
       """.trimMargin()
   }
}
var charactersStats = mutableListOf<CharacterFight>()
var charStats = mutableListOf<String>()
   val fileName: String = "src/main/kotlin/gimli.txt"
   var  characterInfo = mutableListOf<String>()
var lines = File(fileName).readLines()
   for (line in lines){
       val pieces  = line.split("\n")
       characterInfo.add(line)
   }
    charStats.add(characterInfo[0])
   for (stat in charStats){
       var statpieces = stat.split(",")
      var charpieces = CharacterFight(statpieces[0],statpieces[1],statpieces[2].toInt(),statpieces[3].toInt(),statpieces[4].toInt)
       charactersStats.add(charpieces)
   }```

person NooBToCode    schedule 24.10.2020    source источник
comment
то, что у вас есть, выглядит как неструктурированный CSV. Я бы удалил \n из файла, а затем просто прочитал его как обычный csv с одной строкой (вам может потребоваться обрезать целые числа, потому что у вас есть пробелы, или заменить ,space на ,).   -  person Alex.T    schedule 24.10.2020
comment
Это было бы неплохо, но я должен прочитать файл как есть.   -  person NooBToCode    schedule 24.10.2020


Ответы (1)


Чтобы избежать шаблонного toString() кода, рассмотрите возможность использования классов данных:

data class CharacterFight(var name: String, var race: String, var hitpoints: Int, var strength: Int, var agility: Int)

Предполагая, что два других класса

data class Weapon(val name: String, val value: Int)
data class Armor(val name: String, val value: Int)

Десериализацию CSV можно выполнить следующим образом (использование объявлений деструктуризации делает код более читабельно, но явное toInt() преобразование на определенных передаваемых аргументах все же не избежать):

fun deserializeCSV(fileName: String): Triple<CharacterFight, Weapon, Armor> {
    val (characterInfo, weaponInfo, armorInfo) = File(fileName).readLines().map { it.split(",") }
    val character = run { //create separate scope to avoid clash of name variables
        val (name, race, hitpointsStr, strengthStr, agilityStr) = characterInfo
        CharacterFight(name, race, hitpointsStr.toInt(), strengthStr.toInt(), agilityStr.toInt())
    }
    val weapon = run { //create separate scope to avoid clash of name variables
        val (name, valueStr) = weaponInfo
        Weapon(name, valueStr.toInt())
    }
    val armor = run { //create separate scope to avoid clash of name variables
        val (name, valueStr) = armorInfo
        Armor(name, valueStr.toInt())
    }
    return Triple(character, weapon, armor)
}

Если предоставленный формат CSV не является жестким требованием, я бы рекомендовал вместо этого использовать JSON:

{"name":"Gimli","race":"dwarf","hitpoints":90,"strength":40,"agility":3}
{"name":"Axe","value":25}
{"name":"Plate male","value":85}

Затем с помощью библиотеки kotlinx.serialization десериализация довольно проста:

//don't forget to add `@Serializable` annotation to all deserializable classes

fun deserializeJSON(fileName: String): Triple<CharacterFight, Weapon, Armor> {
    val (characterInfo, weaponInfo, armorInfo) = File(fileName).readLines()
    val character: CharacterFight = Json.decodeFromString(characterInfo)
    val weapon: Weapon = Json.decodeFromString(weaponInfo)
    val armor: Armor = Json.decodeFromString(armorInfo)
    return Triple(character, weapon, armor)
}
person Михаил Нафталь    schedule 24.10.2020
comment
Как мне это сделать, если я хочу, чтобы название оружия и брони были в отдельном классе? - person NooBToCode; 24.10.2020
comment
Вы имеете в виду что-то вроде data class WeaponName(val name: String) и data class Weapon(val name: WeaponName, val value: Int)? Затем вам нужно также пометить WeaponName как @Serializable и соответствующим образом настроить JSON: {"name": {"name": "Axe"},"value":25}. - person Михаил Нафталь; 24.10.2020
comment
Определите любую структуру данных, которую вы хотите, затем попробуйте print(Json.encodeToString()) ее с некоторыми фиктивными данными и посмотрите, как должен выглядеть JSON, чтобы его можно было десериализовать обратно. - person Михаил Нафталь; 24.10.2020