ZetCode

F# 正则表达式

最后修改时间 2025 年 5 月 1 日

在本文中,我们将展示如何在 F# 中使用正则表达式。

正则表达式

正则表达式,通常缩写为 regex 或 regexp,是用于文本搜索、模式匹配和高级文本操作的强大工具。它们允许开发人员使用文字字符和特殊符号的组合来定义复杂的搜索模式。正则表达式在各种工具中得到广泛支持,例如 grepsed,文本编辑器如 viEmacs,以及包括 Python、JavaScript 和 F# 在内的编程语言。

在 .NET 生态系统中,正则表达式通过位于 System.Text.RegularExpressions 命名空间中的强大内置 API 来支持。该 API 提供了一套全面的类和方法来处理正则表达式,使开发人员能够轻松执行模式匹配、文本替换和字符串拆分等任务。

正则表达式定义了字符串的搜索模式,可以从简单的文本匹配到涉及量词、分组和断言的高度复杂模式。 .NET 中的 Regex 类表示一个不可变的正则表达式,并作为正则表达式操作的主要入口点。它包含诸如 IsMatch(用于检查字符串是否匹配模式)、Replace(用于替换匹配的文本)和 Split(用于根据模式拆分字符串)之类的方法。这些功能使正则表达式成为文本处理和数据验证任务不可或缺的工具。

F# isMatch

isMatch 方法指示正则表达式是否在输入字符串中找到匹配项。

main.fsx
open System.Text.RegularExpressions

let words =
    [ "Seven"
      "even"
      "Maven"
      "Amen"
      "eleven" ]

let rx = Regex(@".even", RegexOptions.Compiled)

words
|> List.map
    (fun e ->
        if rx.IsMatch(e) then
            printfn $"{e} matches"
        else
            printfn $"{e} does not match")

在示例中,我们有一个包含五个单词的列表。我们检查哪些单词匹配 .even 正则表达式。

let words =
    [ "Seven"
      "even"
      "Maven"
      "Amen"
      "eleven" ]

我们定义了一个单词列表。

let rx = Regex(@".even", RegexOptions.Compiled)

我们创建了 .even 正则表达式。RegexOptions.Compiled 选项指定正则表达式被编译到程序集中。这会提高执行速度,但会增加启动时间。点(.)元字符代表文本中的任何单个字符。

words
|> List.map
    (fun e ->
        if rx.IsMatch(e) then
            printfn $"{e} matches"
        else
            printfn $"{e} does not match")

我们将给定的 lambda 函数应用于列表的元素。如果单词与正则表达式匹配,IsMatch 方法将返回 true。

λ dotnet fsi main.fsx
Seven matches
even does not match
Maven does not match
Amen does not match
eleven matches

F# 正则表达式交替

交替运算符 | 使能够创建具有多个选项的正则表达式。

main.fsx
open System.Text.RegularExpressions

let users = ["Jane"; "Thomas"; "Robert";
    "Lucy"; "Beky"; "John"; "Peter"; "Andy"]

let rx = Regex("Jane|Beky|Robert", RegexOptions.Compiled)
users |> List.filter rx.IsMatch |> List.iter (printfn "%s")

列表中有九个名字。

let rx = Regex("Jane|Beky|Robert", RegexOptions.Compiled)

正则表达式查找 "Jane"、"Beky" 或 "Robert" 字符串。

users |> List.filter rx.IsMatch |> List.iter (printfn "%s")

我们通过对列表中的每个元素应用 IsMatch 来过滤列表,然后打印所有匹配的值。

λ dotnet fsi main.fsx
Jane
Robert
Beky

F# 正则表达式 Matches

Matches 方法搜索输入字符串中正则表达式的所有出现,并返回所有匹配项。

main.fsx
open System.Text.RegularExpressions

let content =
    @"Foxes are omnivorous mammals belonging to several genera
of the family Canidae. Foxes have a flattened skull, upright triangular ears,
a pointed, slightly upturned snout, and a long bushy tail. Foxes live on every
continent except Antarctica. By far the most common and widespread species of
fox is the red fox."


let found =
    seq {
        for m in Regex.Matches(content, "(?i)fox(es)?") do
            yield m.Value, m.Index
    }

found
|> Seq.iter (fun (e, idx) -> printfn "%s at %d" e idx)

在示例中,我们查找 fox 这个词的所有出现。

let found =
    seq {
        for m in Regex.Matches(content, "(?i)fox(es)?") do
            yield m.Value, m.Index
    }

我们将 content 字符串与指定的正则表达式进行匹配。该正则表达式不区分大小写,并且可能包含其复数形式。将创建匹配值及其索引的序列。

found
|> Seq.iter (fun (e, idx) -> printfn "%s at %d" e idx)

我们遍历序列并打印找到的匹配项及其索引。

λ dotnet fsi main.fsx
Foxes at 0
Foxes at 80
Foxes at 194
fox at 292
fox at 307

F# 正则表达式单词边界

元字符 \b 是一个锚点,它匹配一个称为单词边界的位置。它允许搜索整个单词。

main.fsx
open System.Text.RegularExpressions

let text = "This island is beautiful"

let rx = Regex(@"\bis\b", RegexOptions.Compiled)

let matches =
    rx.Matches(text)
    |> Seq.map (fun m -> m.Value, m.Index)

matches
|> Seq.iter (fun (e, idx) -> printfn "%s at %d" e idx)

我们查找 is 这个词,但不是 This 和 island 这两个词。

let rx = Regex(@"\bis\b", RegexOptions.Compiled)

使用两个 \b 元字符,我们搜索 is 这个完整的单词。

λ dotnet fsi main.fsx
is at 12

F# 正则表达式货币符号

\p{Sc} 正则表达式可用于查找货币符号。

main.fsx
open System
open System.Text.RegularExpressions

Console.OutputEncoding = Text.Encoding.UTF8

let content = @"Currency symbols: ฿ Thailand bath, ₹  Indian rupee,
    ₾ Georgian lari, $ Dollar, € Euro, ¥ Yen, £ Pound Sterling";

let pattern = @"\p{Sc}";

let rx = Regex(pattern, RegexOptions.Compiled)
let matches = rx.Matches(content)
              |> Seq.map (fun m -> m.Value, m.Index)

matches
|> Seq.iter (fun (e, idx) -> printfn "%s at %d" e idx)

在程序中,我们查找货币符号。

λ dotnet fsi main.fsx
฿ at 18
₹ at 35
₾ at 57
$ at 74
€ at 84
¥ at 92
£ at 99

F# 正则表达式捕获组

圆括号用于创建捕获组。这使我们能够将量词应用于整个组,或将交替限制为正则表达式的一部分。

main.fsx
open System.Text.RegularExpressions

let sites =
    [ "webcode.me"
      "zetcode.com"
      "spoznaj"
      "freebsd.org"
      "netbsd.org" ]

let rx =
    Regex(@"(\w+)\.(\w+)", RegexOptions.Compiled)

let check e =
    let m = rx.Match(e)
    (m.Value, m.Groups[1], m.Groups[2])

let found = sites |> List.map check

printfn "%A" found

在程序中,我们使用分组将域名分成两部分。

let rx =
    Regex(@"(\w+)\.(\w+)", RegexOptions.Compiled)

我们用括号定义了两个组。

let check e =
    let m = rx.Match(e)
    (m.Value, m.Groups[1], m.Groups[2])

Value 属性返回整个匹配的字符串;它等于 match.Groups[0]。组通过 Groups 属性进行访问。

λ dotnet fsi main.fsx
[("webcode.me", webcode, me); ("zetcode.com", zetcode, com); ("", , );
 ("freebsd.org", freebsd, org); ("netbsd.org", netbsd, org)]

活动模式

我们可以将正则表达式与活动模式和匹配表达式一起使用。*活动模式*是输入数据的命名分区,可以在后面的模式匹配表达式中使用。

main.fsx
open System.Text.RegularExpressions

let (|RegEx|_|) p i =
    let m = Regex.Match(i, p)

    if m.Success then
        Some m.Groups
    else
        None

let checkrgx (msg) =
    match msg with
    | RegEx @"\d+" g -> printfn "Digit: %A" g
    | RegEx @"\w+" g -> printfn "Word : %A" g
    | _ -> printfn "Not recognized"


checkrgx "an old falcon"
checkrgx "1984"
checkrgx "3 hawks"

在示例中,我们在模式匹配中使用活动模式和正则表达式。

let (|RegEx|_|) p i =
    let m = Regex.Match(i, p)

    if m.Success then
        Some m.Groups
    else
        None

我们定义了 RegEx 名称,它将模式与给定的输入进行匹配。

let checkrgx (msg) =
    match msg with
    | RegEx @"\d+" g -> printfn "Digit: %A" g
    | RegEx @"\w+" g -> printfn "Word : %A" g
    | _ -> printfn "Not recognized"

定义的名称在匹配表达式中使用。

λ dotnet fsi main.fsx
Word : seq [an]
Digit: seq [1984]
Digit: seq [3]

在本文中,我们已经学习了如何在 F# 中使用正则表达式。

作者

我叫 Jan Bodnar,是一名充满激情的程序员,拥有丰富的编程经验。我自 2007 年以来一直在撰写编程文章。至今,我已撰写了 1400 多篇文章和 8 本电子书。我在编程教学方面拥有十多年的经验。