如何生成从每个可能的字符中提取的字符串?

How to generate strings drawn from every possible character?

目前我正在生成这样的字符串:

arbStr :: Gen String
arbStr = listOf $ elements (alpha ++ digits)
  where alpha = ['a'..'z']
        digits = ['0'..'9']

但显然这只会从 alpha num 字符生成字符串。我怎样才能从所有可能的字符生成?

由于 Char 是 Bounded 和 Enum 的实例(通过向 GHCI 询问 :i Char 来确认这一点),您可以简单地写

[minBound..maxBound] :: [Char]

获取所有合法字符的列表。显然,这不会导致有效的随机访问!因此,您可以使用 Data.Char.ord :: Char -> Int 将边界转换为 Int,并使用 QuickCheck 的功能从整数范围转换为 select,然后映射回具有 Data.Chra.chr :: Int -> Char 的字符。

CharEnumBounded 类型类的实例,您可以使用 arbitraryBoundedEnum :: (Bounded a, Enum a) => Gen a 函数:

import Test.QuickCheck(Gen, arbitraryBoundedEnum, listOf)

arbStr :: Gen String
arbStr = listOf arbitraryBoundedEnum

例如:

Prelude Test.QuickCheck> sample arbStr
""
""
"1749"
"34650384511062154544"
"1263637835056922982902442"
""
"6116875018810014369768173490547178243132098"
"6281"
"992929604287329754929196902964687280570924763429957904579821"
"6024639943826142989279772335608818407252710506086448592624870104441595"
"2370899791815"

或者您可以使用 Arbitrary Char 类型类中的 arbitrary

import Test.QuickCheck(Gen, arbitrary, listOf)

arbStr :: Gen String
arbStr = listOf arbitrary

请注意 Chararbitrary 的实现使得 ASCII 字符比非 ASCII 字符更常见(三倍),因此 "distribution" 不同。

当我们喜欢的时候

λ> length ([minBound..maxBound] :: [Char])
1114112

我们得到所有字符的数量并说哇..!如果您认为列表太大,那么您可能总是喜欢 drop x . take y 来限制范围。

因此,如果您需要 n 许多随机字符,只需 shuffle :: [a] -> IO [a] 列表并从该随机列表中执行 take n

编辑:

当然...因为洗牌可能很昂贵,所以我们最好选择一个聪明的策略。最好随机限制所有字符列表。所以就

  1. 制作limits = liftM sort . mapM randomRIO $ replicate 2 (0,1114112) :: (Ord a, Random a, Num a) => IO [a]

  2. limits >>= \[min,max] -> return . drop min . take max $ ([minBound..maxBound] :: [Char])

  3. 最后只从 项目 2 的结果中随机抽取 n 个像 Char 一样的 liftM . take n