ZetCode

F# 字符串

最后修改日期:2025 年 5 月 1 日

在本文中,我们将展示如何在 F# 中处理字符串。

在 F# 中,字符串是 Unicode 字符序列。字符串用于表示文本,是 F# 中最基本的数据类型。字符串可以存储字母、数字、符号,甚至 emoji 字符。当字符串字面量出现在源代码中时,它被称为字符串字面量,并用双引号括起来,例如:"一只老猎鹰"

F# 中的字符串是对象,基于 .NET 的 System.String 类型,该类型是不可变的。这意味着一旦创建了字符串,就无法更改它;任何看似修改字符串的操作实际上都会创建一个新字符串。对于需要频繁构建或修改字符串的场景(例如在循环中),您可以使用 System.Text.StringBuilder 类,它是一个可变的字符序列,对于重复修改更有效。

F# 中的 string 关键字是 System.String 的别名。您可以在代码中使用 stringSystem.String;它们指向同一个类型。

F# 字符串简单示例

下面是一个简单的 F# 字符串示例。

main.fsx
let w1 = "an old falcon"
let w2 = "an" + " old" + " falcon"

printfn "%s" w1
printfn "%s" w2

我们定义一个普通字符串并打印它,然后连接两个字符串。

let w1 = "an old falcon"

字符串用两个双引号分隔。

let w2 = "an" + " old" + " falcon"

我们使用 + 运算符连接三个字符串。

printfn "%s" w1

字符串使用 printf 打印到终端。

λ dotnet fsi main.fsx
an old falcon
an old falcon

F# 字符串转整数

int 内置函数将字符串转换为整数。

main.fsx
let vals = ("2", 1, "4", 6, "11")

let a, b, c, d, e = vals
let sum = int a + b + int c + d + int e

printfn "%d" sum

我们有一个值元组:整数和字符串。我们想计算所有值的总和。

let a, b, c, d, e = vals

我们将元组解构为五个变量。

let sum = int a + b + int c + d + int e

我们对变量求和;字符串使用 int 转换为整数。

λ dotnet fsi main.fsx
24

F# 字符串重复

在下一个示例中,我们将展示如何在 F# 中重复字符串。

main.fsx
printfn "%s" (String.replicate 5 "falcon ")
printfn "%s" (String.concat " " (Array.create 5 "falcon"))

字符串可以使用 String.replicateArray.createString.concat 进行重复。

$ dotnet fsi main.fsx
Name: John Doe, Age: 34

F# 字符串插值

$ 特殊字符前缀将字符串字面量标识为插值字符串。插值字符串是可能包含插值表达式的字符串字面量。

main.fsx
open System

let name = "John Doe"
let occupation = "gardener"

let msg = $"{name} is an {occupation}"
printfn $"{msg}"

printfn $"5 * 8 = {5 * 8}"

let now = DateTime.Now
printfn $"Hello, {name}! Today is {now.DayOfWeek}."

我们创建了几个插值字符串。

let msg = $"{name} is an {occupation}"
printfn "%s" msg

我们构建一个包含两个变量内容的字符串:nameoccupation。它们放在花括号之间。

printfn $"5 * 8 = {5 * 8}"

插值字符串可以包含表达式。

let now = DateTime.Now
printfn $"Hello, {name}! Today is {now.DayOfWeek}."

我们插值了一个 DateTime 值。

λ dotnet fsi main.fsx
John Doe is an gardener
5 * 8 = 40
Hello, John Doe! Today is Monday.

我们可以使用类型化格式说明符来强制类型安全。

main.fsx
let name = "John Doe"
let age = 34

printfn $"Name: %s{name}, Age: %d{age}"

%s 说明符用于字符串,%d 用于整数。

F# 字符串转义序列

转义字符是执行特定操作的特殊字符。例如,\n 字符开始一个新行。

main.fsx
printfn("Three\t bottles of wine")
printfn("He said: \"I love ice skating\"")
printfn("Line 1:\nLine 2:\nLine 3:")

我们有一个包含转义字符的示例。

printfn("Three\t bottles of wine")

\t 转义字符插入一个制表符。

printfn("He said: \"I love ice skating\"")

我们通过转义来在字符串字面量中插入双引号。

printfn("Line 1:\nLine 2:\nLine 3:")

使用 \n,我们创建了三行。

λ dotnet fsi main.fsx
Three    bottles of wine
He said: "I love ice skating"
Line 1:
Line 2:
Line 3:

F# 字符串 Contains

Contains 方法检查字符串是否包含给定的字符串。

main.fsx
let msg = "an old falcon"

let word = "falcon"
let r = msg.Contains("falcon")

if r then 
    printfn $"The string contains {word}"
else
    printfn $"The string does not contain {word}"

在程序中,我们检查一只老猎鹰字符串是否包含猎鹰一词。

λ dotnet fsi main.fsx
The string contains falcon

F# 字符串 StartsWith/EndsWith

我们可以使用 StartsWithEndsWith 函数检查字符串是否以某个字符开头/结尾。

main.fsx
let words = ["sky"; "war"; "water"; "cup"; "cloud"; "warm"; "rock"; "try"]

let res = words |> List.filter (fun e -> e.StartsWith 'w')
printfn "%A" res

let res2 = words |> List.filter (fun e -> e.EndsWith 'r')
printfn "%A" res2

我们有一系列单词。我们选择所有以w开头然后以r结尾的单词。

λ dotnet fsi main.fsx
["war"; "water"; "warm"]
["war"; "water"]

F# 逐字字符串

逐字字符串不解释转义序列。它们前面有 @ 字符。我们可以用它们创建多行字符串。

main.fsx
printfn "%s" @"deep \t forest"
printfn "%s" @"C:\Users\Admin\Documents"

let text = @"
    Not marble, nor the gilded monuments
Of princes, shall outlive this powerful rhyme;
But you shall shine more bright in these contents
Than unswept stone, besmeared with sluttish time."

printfn "%s" text

在此代码示例中,我们使用逐字字符串。

printfn "%s" @"deep \t forest"

\t 特殊字符未被解释;它只会被打印到控制台。

printfn "%s" @"C:\Users\Admin\Documents"

当我们处理路径时,逐字字符串很方便。

let text = @"
    Not marble, nor the gilded monuments
Of princes, shall outlive this powerful rhyme;
But you shall shine more bright in these contents
Than unswept stone, besmeared with sluttish time."

逐字字符串允许我们创建多行字符串。

λ dotnet fsi main.fsx
deep \t forest
C:\Users\Admin\Documents

    Not marble, nor the gilded monuments
Of princes, shall outlive this powerful rhyme;
But you shall shine more bright in these contents
Than unswept stone, besmeared with sluttish time.

F# 将整数数组转换为字符串

在下一个示例中,我们将整数数组转换为字符串。

main.fsx
let nums = [| 2; 4; 6; 8 |]

let output =
    nums
    |> Array.map (sprintf "%i")
    |> String.concat ","

printfn $"{output}"

我们将 sprintf 函数映射到数组的每个元素;然后我们将字符串元素传递给 String.concat 函数。

λ dotnet fsi main.fsx
2,4,6,8

F# 构建/格式化字符串

有几种方法可以构建或格式化字符串。

main.fsx
open System
open System.Text

let name = "John Doe"
let age = 33

let msg1 = name + " is " + string age + " years old"
printfn $"{msg1}"

let msg2 = sprintf "%s is %d years old" name age
printfn $"{msg2}"

let msg3 = $"{name} is {age} years old"
printfn $"{msg3}"

let msg4 = String.Format("{0} is {1} years old", name, age)
printfn $"{msg4}"

let builder = StringBuilder()
let msg5 = builder.AppendFormat("{0} is {1} years old", name, age)
printfn $"{msg5}"

该示例构建了五个字符串。

let msg1 = name + " is " + string age + " years old"
printfn $"{msg1}"

可以使用 + 运算符将字符串连接起来。

let msg2 = sprintf "%s is %d years old" name age
printfn $"{msg2}"

我们可以使用 sprintf 函数及其格式说明符。

let msg4 = String.Format("{0} is {1} years old", name, age)
printfn $"{msg4}"

另一个选择是 .NET String.Format 函数。

let builder = StringBuilder()
let msg5 = builder.AppendFormat("{0} is {1} years old", name, age)
printfn $"{msg5}"

最后,我们可以使用 StringBuilder 类型。

λ dotnet fsi main.fsx
John Doe is 33 years old
John Doe is 33 years old
John Doe is 33 years old
John Doe is 33 years old
John Doe is 33 years old

F# 枚举 rune

EnumerateRunes 方法枚举字符串中的 rune。Rune 类型精确对应一个 Unicode 标量值。

main.fsx
open System.Text

let text = "🐄🐘🐫🐑🦍🐯";
let runes = text.EnumerateRunes()

for rune in runes do

    printfn $"{rune}"

我们遍历字符串字面量中的 emoji。

λ dotnet fsi main.fsx
🐄
🐘
🐫
🐑
🦍
🐯

在本文中,我们已处理了 F# 中的字符串。

作者

我的名字是 Jan Bodnar,我是一名热情的程序员,拥有丰富的编程经验。我从 2007 年开始撰写编程文章。至今,我已撰写了 1400 多篇文章和 8 本电子书。我在教学编程方面有十多年的经验。