从 unicode 字符串中获取随机 emoji/character

Getting a random emoji/character from a unicode string

我的目标是在 F# 中从列表中获取随机表情符号。

我是这样开始的:

let pickOne (icons: string) : char = icons.[Helpers.random.Next(icons.Length)]
let happySymbols = ""
let sadSymbols   = ""

那是行不通的,因为:

"".Length

是 returning 44 作为长度 returns 字符串中的字符数,这不适用于 unicode 字符。 我不能只除以 2,因为有时我可能会在字符串中添加一些单字节字符。

索引也不起作用:

let a = ""
a.[0]

不会 return 但我得到了一些未知的字符符号。

因此,B 计划是:让我们将其设为数组而不是字符串:

let a = [| ''; ''; ''; ''; ''; ''; ''; ''; ''; ''; ''; ''; ''; ''; ''; ''; ''; ''; ''; ''; ''; '' |]

这不是编译,我得到:

Parse error Unexpected quote symbol in binding. Expected '|]' or other token.

这是为什么?

无论如何,我可以制作一个字符串列表并让它工作,但我很好奇:有没有 "proper" 方法让第一个工作并从 unicode 中获取随机 unicode 字符字符串?

.NET 中的所有字符串都是 16 位 unicode 字符串。 那就是char的定义:

Represents a character as a UTF-16 code unit.

所有字符占用最小编码大小(UTF-16 为 2 个字节),最多不超过所需的字节数。表情符号不适合 2 个字节,因此它们对齐到 4 个字节或 2 个字符。

那么解决方法是什么?对齐(4)所有的东西! (在这里插入 GCC 笑话)。

首先我们将所有内容转换成UTF32:

let utf32 (source: string) =
    Encoding.Convert(Encoding.Unicode, Encoding.UTF32, Encoding.Unicode.GetBytes(source))

然后我们可以任意挑选"character":

let pick (arr: byte[]) index = 
    Encoding.UTF32.GetString(arr, index * 4, 4)

测试:

let happySymbols = "YTHO"

pick (utf32 happySymbols) 0;;
val it : string = ""

> pick (utf32 happySymbols) 22;;
val it : string = "Y"

对于实际长度,只需 div 乘以 4。

let surpriseMe arr =
    let rnd = Random()
    pick arr (rnd.Next(0, arr.Length / 4))

嗯嗯

> surpriseMe (utf32 happySymbols);;
val it : string = ""

Asti 的回答符合您的目的,但我对我们在这个问题上的进展不太满意。我想我被答案中的 "proper" 这个词给迷住了。在各个地方进行了大量研究之后,我对这个方法感到好奇String.EnumerateRunes, which again lead me to the type Rune。该类型的文档对正确的字符串处理以及 .NET 中 Unicode UTF-8 字符串中的内容特别有启发性。我也在 LINQPad 上试验过,得到了这个。

let dump x = x.Dump()
let runes = "abcABCæøåÆØÅ₅茨茧茦茥".EnumerateRunes().ToArray()
runes.Length |> dump
// 20
runes |> Array.iter (fun rune -> dump (string rune))
// a b c A B C æ ø å Æ Ø Å    ₅ 茨 茧 茦 茥
dump runes
// see screenshot
let smiley = runes.[13].ToString()
dump smiley
//