如何使用整数和特殊字符格式化字符串

时间:2019-01-25 16:40:50

标签: kotlin

在跳高比赛中,我对运动员的成绩有一定的了解。这里,+表示成功尝试,%不成功,-跳过。高度和相应的尝试用空格隔开。我需要读取字符串并返回最大高度,如果不存在或字符串格式损坏,则返回-1。 例如:

  1. "220 + 224 %+ 228 %- 230 + 232 %%- 234 %".// result in 230
  2. "226 +" // result is 226
  3. "???" // result is -1

我尝试使用正则表达式,但没有取得太大的成功。

fun bestHighJump(jumps: String): Int {
    var result = 0
    val jumpsSplitted = jumps.split(" ")
    val regStr = Regex("""[.+\d]""")
    for (item in jumpsSplitted) {
        if (regStr.containsMatchIn(item)) result += item
    }
    //Don't know what to do next
}

帮助解决问题,如果不是很困难,请推荐一些资源,使我可以很好地学习字符串格式设置主题。

3 个答案:

答案 0 :(得分:2)

(鉴于问题已被改写。)

按照我现在的理解,该字符串应包含整数和符号,并且我们想要最大的整数,后跟“ +”。

我可以通过将字符串拆分成单词,然后查看单词的来实现。我们可以使用zipWithNext()函数来完成此操作,该函数给出所有相邻对的列表。然后,我们可以filter()仅选择第二个单词为“ +”的单词,mapNotNull()尽可能将这样的单词对中的第一个单词转换为Int(忽略{{1 }}(不是有效整数),然后取其中的null。 (如果没有,max()返回max(),所以我们可以使用Elvis运算符代替-1。)

null

(我将其作为fun String.bestHighJump() = split(" ") .zipWithNext() .filter{ it.second == "+" } .mapNotNull{ it.first.toIntOrNull() } .max() ?: -1 的扩展函数,主要是因为它看起来很合适;它还避免了必须声明然后使用参数的情况。但是普通函数的工作方式几乎相同)

要使这更加惯用,最好删除Elvis运算符,如果没有匹配的分数,则直接返回String;这使情况对于呼叫者来说更加明显,然后呼叫者可以决定如何处理该情况。

由于您正在查看正则表达式,因此这是使用其中一种的替代解决方案:

null

这短了一行,但是我认为它还不清楚。以我的经验,正则表达式通常很难正确设置,调试和维护,因此我更喜欢其他方法。 (为了进行比较,第一个版本是第一次工作,而regex版本却进行了许多尝试!)

此处正则表达式匹配一个成功的结果(一个或多个数字,后跟一个空格,一个fun String.bestHighJump() = Regex("""([0-9]+) [+]\B""") .findAll(this) .map{ it.groupValues[1].toInt() } .max() ?: -1 ,然后一个单词边界。(需要后者,因为我们不知道此结果是否是正则表达式贪婪地匹配,因此我们也不需要一开始就使用它。)

+搜索整个字符串,并返回一个匹配序列;然后,我们从每个数字中取出第一组(即数字),将其转换为整数(如果正则表达式有效,则这次无需处理无效数字),并像以前一样取最大值。

(关于如何处理具有多个字符的成功指示符的问题仍然不清楚。我假设我们只想对成功指示符只是一个字符'+'的结果进行计数。还包括在'%'和/或其他字符中包含'+'的情况,然后可以对这两个函数进行调整。但是同样,正则表达式将更难做到。)

关于在哪里学习这种东西,我假设您已经了解Kotlin docs。 (并且我推荐使用Kotlin In Action书来学习该语言。)根据您的需求,有不同的字符串处理方法,因此很难推荐-但基本原理并非特定于Kotlin,因此可能有很多地方可以看。而且,如果您的案子比较棘手,可以随时将其发布为另一个问题!

答案 1 :(得分:2)

首先,您需要修剪和清除多个相邻空格中的参数jumps
然后拆分后,创建2个列表:

第一个包含高度
第二个包含尝试

有必要检查第一个列表是否包含有效整数
并且这两个列表的大小相同
然后,通过删除第二个列表的每个项目中所有出现的%-
您将获得最后+个项目的索引
index 用于从第一个列表中获取相应的高度。

fun bestHighJump(jumps: String): Int {
    val jumpsSplitted = jumps.trim().replace(Regex("\\s\\s+"), " ").split(" ")
    if (jumpsSplitted.size < 2 || jumpsSplitted.size % 2 == 1)
        return -1

    val heights = jumpsSplitted.filterIndexed { i, _ ->  (i % 2 == 0)}.mapNotNull { it.toIntOrNull() }
    val attempts = jumpsSplitted.filterIndexed { i, _ ->  (i % 2 == 1)}
    if (heights.size != attempts.size)
        return -1

    val index = attempts
            .map { it.replace("%", "").replace("-", "") }
            .indexOfLast { it == "+" }

    return if (index == -1) -1 else heights[index]
}


这个

val jumps1 = "220 + 224 %+ 228 %- 230 + 232 %%- 234 %"
println(bestHighJump(jumps1))

将打印230

这个

val jumps2 = "226 +"
println(bestHighJump(jumps2))

将打印226

这个

val jumps3 = "???"
println(bestHighJump(jumps3))

将打印-1

答案 2 :(得分:1)

使用正则表达式是个好主意。团体在这里特别方便。

([\\d]{1,3})([ +\\-%]*)

正则表达式将在其第一组中匹配任何1-3位数字,并在第二组中匹配该尝试的结果。

您用Sequence<MatchResult>检索了findAll,然后过滤并映射了感兴趣的值。

最后,您将返回成功尝试的最大值;如果输入字符串无效或不包含成功跳转,则返回-1。

fun bestHighJump(jumps: String): Int {
    val attempts = Regex("([\\d]{1,3})([ +\\-%]*)").findAll(jumps)

    val list = attempts.filter {
        it.groups[2]?.value?.let {
            '+' in it
        } == true
    }.map {
        it.groups[1]?.value
    }.mapNotNull { it?.toInt() }.toList()

    return if (list.isEmpty()) {
        -1
    } else {
        list.max()!!
    }
}

请注意,在Kotlin的MatchGroupCollection中,第一组的索引为1,第二组的索引为2,因为索引为0的组是两个组的组合。