【问题标题】:Idiomatic way to generate a random alphanumeric string in Kotlin在 Kotlin 中生成随机字母数字字符串的惯用方法
【发布时间】:2018-04-07 05:14:54
【问题描述】:

我可以生成一定范围内的随机数字序列,如下所示:

fun ClosedRange<Int>.random() = Random().nextInt(endInclusive - start) +  start
fun generateRandomNumberList(len: Int, low: Int = 0, high: Int = 255): List<Int> {
  (0..len-1).map {
    (low..high).random()
  }.toList()
}

那么我将不得不扩展List

fun List<Char>.random() = this[Random().nextInt(this.size)]

那我可以做:

fun generateRandomString(len: Int = 15): String{
  val alphanumerics = CharArray(26) { it -> (it + 97).toChar() }.toSet()
      .union(CharArray(9) { it -> (it + 48).toChar() }.toSet())
  return (0..len-1).map {
      alphanumerics.toList().random()
  }.joinToString("")
}

但也许有更好的方法?

【问题讨论】:

    标签: kotlin


    【解决方案1】:

    这是它的加密安全版本,或者我相信:

    fun randomString(len: Int): String {
        val random = SecureRandom()
        val chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789".toCharArray()
        return (1..len).map { chars[random.nextInt(chars.size)] }.joinToString("")
    }
    

    【讨论】:

      【解决方案2】:

      您可以使用 apache-commons-lang3

      中的RandomStringUtils.randomAlphanumeric(min: Int, max: Int) -&gt; String

      【讨论】:

        【解决方案3】:

        这个问题已经很老了,但我认为另一个很好的解决方案(应该从 Kotlin 1.3 开始工作)如下:

        // Just a simpler way to create a List of characters, as seen in other answers
        // You can achieve the same effect by declaring it as a String "ABCDEFG...56789"
        val alphanumeric = ('A'..'Z') + ('a'..'z') + ('0'..'9')
        
        fun generateAlphanumericString(length: Int) : String {
            // The buildString function will create a StringBuilder
            return buildString {
                // We will repeat length times and will append a random character each time
                // This roughly matches how you would do it in plain Java
                repeat(length) { append(alphanumeric.random()) }
            }
        }
        

        【讨论】:

          【解决方案4】:

          Kotlin 1.3 开始,您可以这样做:

          fun getRandomString(length: Int) : String {
              val allowedChars = ('A'..'Z') + ('a'..'z') + ('0'..'9')
              return (1..length)
                  .map { allowedChars.random() }
                  .joinToString("")
          }
          

          【讨论】:

            【解决方案5】:

            我使用以下代码生成随机单词和句子。

            val alphabet: List<Char> = ('a'..'z') + ('A'..'Z') + ('0'..'9')
            
            val randomWord: String = List((1..10).random()) { alphabet.random() }.joinToString("")
            
            val randomSentence: String = (1..(1..10).random()).joinToString(" ") { List((1..10).random()) { alphabet.random() }.joinToString("") }
            

            【讨论】:

              【解决方案6】:

              为定义长度定义它:

              val randomString = UUID.randomUUID().toString().substring(0,15)
              

              其中15 是字符数

              【讨论】:

                【解决方案7】:

                没有JDK8:

                fun ClosedRange<Char>.randomString(length: Int) = 
                    (1..length)
                        .map { (Random().nextInt(endInclusive.toInt() - start.toInt()) + start.toInt()).toChar() }
                        .joinToString("")
                

                用法:

                ('a'..'z').randomString(6)
                

                【讨论】:

                  【解决方案8】:

                  使用 Kotlin 1.3 中的 Collection.random()

                  // Descriptive alphabet using three CharRange objects, concatenated
                  val alphabet: List<Char> = ('a'..'z') + ('A'..'Z') + ('0'..'9')
                  
                  // Build list from 20 random samples from the alphabet,
                  // and convert it to a string using "" as element separator
                  val randomString: String = List(20) { alphabet.random() }.joinToString("")
                  

                  【讨论】:

                    【解决方案9】:
                    fun randomAlphaNumericString(@IntRange(from = 1, to = 62) lenght: Int): String {
                        val alphaNumeric = ('a'..'z') + ('A'..'Z') + ('0'..'9')
                        return alphaNumeric.shuffled().take(lenght).joinToString("")
                    }
                    

                    【讨论】:

                    • 虽然这可能会解决 OP 的问题(我没有测试过),但 SO 上通常不鼓励仅使用代码的答案。如果您可以包含关于为什么这是问题的答案的描述,那就更好了。谢谢!
                    【解决方案10】:

                    假设您有一组特定的源字符(此 sn-p 中的source),您可以这样做:

                    val source = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
                    java.util.Random().ints(outputStrLength, 0, source.length)
                            .asSequence()
                            .map(source::get)
                            .joinToString("")
                    

                    对于 outputStrLength = 10,它会给出类似“LYANFGNPNI”的字符串。

                    两个重要的位是

                    1. Random().ints(length, minValue, maxValue) 生成 length 个随机数流,每个随机数从 minValuemaxValue-1,以及
                    2. asSequence() 将不是大量有用的 IntStream 转换为更有用的 Sequence&lt;Int&gt;

                    【讨论】:

                    • 作为 Kotlin 新手,我一直在寻找这个解决方案 - 非常酷!但是我会使用source.length 而不是source.length - 1,否则永远不会看到 Z。ints range 参数标记了一个专有的上限。
                    • 很好看。 Java8 API 设计者的一个非常有趣的想法是让这个(几乎)成为 Java 中唯一的唯一绑定描述参数......
                    • 我在.asSequence() 上得到一个未解决的引用,因为IntStream 没有那个方法
                    • @PaulHicks 您可以使用.toArray() 而不是.asSequence(),而无需导入其他方法。
                    • API 24 是 Android 的东西吗?这不是专门针对 Android 的。
                    【解决方案11】:

                    使用 Kotlin 1.3

                    此方法使用所需字符串长度desiredStrLength 的输入作为整数,并返回所需字符串长度的随机字母数字字符串。

                    fun randomAlphaNumericString(desiredStrLength: Int): String {
                        val charPool: List<Char> = ('a'..'z') + ('A'..'Z') + ('0'..'9')
                    
                        return (1..desiredStrLength)
                            .map{ kotlin.random.Random.nextInt(0, charPool.size) }
                            .map(charPool::get)
                            .joinToString("")
                    }
                    

                    如果您更喜欢未知长度的字母数字(或至少像下面我的示例中的 36 那样的相当长的字符串长度),可以使用此方法:

                    fun randomAlphanumericString(): String {
                        val charPool: List<Char> = ('a'..'z') + ('A'..'Z') + ('0'..'9')
                        val outputStrLength = (1..36).shuffled().first()
                    
                        return (1..outputStrLength)
                            .map{ kotlin.random.Random.nextInt(0, charPool.size) }
                            .map(charPool::get)
                            .joinToString("")
                    }
                    

                    【讨论】:

                      【解决方案12】:

                      根据 Paul Hicks 的答案,我想要一个自定义字符串作为输入。在我的情况下,大写和小写字母数字字符。 Random().ints(...) 也不适用于我,因为它需要 Android 上的 API 级别 24 才能使用它。

                      这就是我使用 Kotlin 的 Random 抽象类的方式:

                      import kotlin.random.Random
                      
                      object IdHelper {
                      
                          private val ALPHA_NUMERIC = ('0'..'9') + ('A'..'Z') + ('a'..'z')
                          private const val LENGTH = 20
                      
                          fun generateId(): String {
                              return List(LENGTH) { Random.nextInt(0, ALPHA_NUMERIC.size) }
                                      .map { ALPHA_NUMERIC[it] }
                                      .joinToString(separator = "")
                          }
                      }
                      

                      该过程及其工作原理与此处已发布的许多其他答案相似:

                      1. 生成与源字符串的索引值相对应的长度为LENGTH 的数字列表,在本例中为ALPHA_NUMERIC
                      2. 将这些数字映射到源字符串,将每个数字索引转换为字符值
                      3. 将生成的字符列表转换为字符串,用空字符串作为分隔符将它们连接起来。
                      4. 返回结果字符串。

                      使用简单,像静态函数一样调用即可:IdHelper.generateId()

                      【讨论】:

                        【解决方案13】:

                        我认为最好的方式:

                        fun generateID(size: Int): String {
                            val source = "A1BCDEF4G0H8IJKLM7NOPQ3RST9UVWX52YZab1cd60ef2ghij3klmn49opq5rst6uvw7xyz8"
                            return (source).map { it }.shuffled().subList(0, size).joinToString("")
                        }
                        

                        【讨论】:

                        • 但这不是只是混合了字符(列表的元素),因此每个字符只会被选择一次吗?还是我错过了什么?
                        【解决方案14】:
                        ('A'..'z').map { it }.shuffled().subList(0, 4).joinToString("")
                        

                        【讨论】:

                        • 虽然这可能会回答作者的问题,但它缺少一些解释性文字和/或文档链接。如果没有围绕它们的一些短语,原始代码 sn-ps 并不是很有帮助。您可能还会发现how to write a good answer 非常有帮助。请编辑您的答案 - From Review
                        • 这不会产生带有重复字符的结果,例如aaaaaaxy,因此它不是随机字符串生成器。
                        • 请注意('A'..'z') 还包括字符[、\、]^_`
                        【解决方案15】:

                        懒惰的人会这样做

                        java.util.UUID.randomUUID().toString()
                        

                        这里不能限制字符范围,但我想在很多情况下还是可以的。

                        【讨论】:

                          【解决方案16】:

                          或者使用协程 API 来实现真正的 Kotlin 精神:

                          buildSequence { val r = Random(); while(true) yield(r.nextInt(24)) }
                             .take(10)
                             .map{(it+ 65).toChar()}
                             .joinToString("")
                          

                          【讨论】:

                          • 协程的优点是避免了所有这些高阶函数,并编写了一个简单的循环来完成所有这些函数。 (1..10).forEach { yield(r.nextInt(24) + 65).toChar() }
                          猜你喜欢
                          • 2012-12-29
                          • 2010-09-08
                          • 1970-01-01
                          • 1970-01-01
                          • 2021-04-05
                          • 2011-08-18
                          • 2013-07-26
                          • 2013-08-06
                          • 2011-06-18
                          相关资源
                          最近更新 更多