如何生成从每个可能的字符中提取的字符串?
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
的字符。
Char
是 Enum
和 Bounded
类型类的实例,您可以使用 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
请注意 Char
的 arbitrary
的实现使得 ASCII 字符比非 ASCII 字符更常见(三倍),因此 "distribution" 不同。
当我们喜欢的时候
λ> length ([minBound..maxBound] :: [Char])
1114112
我们得到所有字符的数量并说哇..!如果您认为列表太大,那么您可能总是喜欢 drop x . take y
来限制范围。
因此,如果您需要 n
许多随机字符,只需 shuffle :: [a] -> IO [a]
列表并从该随机列表中执行 take n
。
编辑:
当然...因为洗牌可能很昂贵,所以我们最好选择一个聪明的策略。最好随机限制所有字符列表。所以就
制作limits = liftM sort . mapM randomRIO $ replicate 2 (0,1114112) :: (Ord a, Random a, Num a) => IO [a]
limits >>= \[min,max] -> return . drop min . take max $ ([minBound..maxBound] :: [Char])
最后只从 项目 2 的结果中随机抽取 n
个像 Char
一样的 liftM . take n
。
目前我正在生成这样的字符串:
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
的字符。
Char
是 Enum
和 Bounded
类型类的实例,您可以使用 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
请注意 Char
的 arbitrary
的实现使得 ASCII 字符比非 ASCII 字符更常见(三倍),因此 "distribution" 不同。
当我们喜欢的时候
λ> length ([minBound..maxBound] :: [Char])
1114112
我们得到所有字符的数量并说哇..!如果您认为列表太大,那么您可能总是喜欢 drop x . take y
来限制范围。
因此,如果您需要 n
许多随机字符,只需 shuffle :: [a] -> IO [a]
列表并从该随机列表中执行 take n
。
编辑:
当然...因为洗牌可能很昂贵,所以我们最好选择一个聪明的策略。最好随机限制所有字符列表。所以就
制作
limits = liftM sort . mapM randomRIO $ replicate 2 (0,1114112) :: (Ord a, Random a, Num a) => IO [a]
limits >>= \[min,max] -> return . drop min . take max $ ([minBound..maxBound] :: [Char])
最后只从 项目 2 的结果中随机抽取
n
个像Char
一样的liftM . take n
。