在F#中从字符串中删除字符

5

我有一个List<char>stripchars中。这些字符不应该出现在字符串text中。所以我把它变成了可变的。

所以我做了这样的事情:

stripchars |> Seq.iter(
    fun x ->
        text <- text.Replace(x, ' ')
    )

然后我收到了一个错误提示,说text是一个可变变量在无效的方式下使用。现在我去看这篇帖子,并得出以下结论:

let s = ref text    
stripchars |> Seq.iter(
    fun ch ->
        printfn "ch: %c" ch
        printfn "resultant: %s" !s
        s :=  (!s).Replace(ch, ' ')
    )

这样仍不能改变text的状态。正确的方法是什么?


请参见http://rosettacode.org/wiki/Strip_a_set_of_characters_from_a_string#F.23 - Ruben Bartelink
4个回答

6

因为没有人发布过这个问题,所以 Core.String 模块包含你正在寻找的方法。

要用空格(或其他单个字符)替换给定字符,请使用 String.map

let strip chars = String.map (fun c -> if Seq.exists((=)c) chars then ' ' else c)

strip "xyz" "123x4y5z789" // 123 4 5 789

要完全删除给定的字符,请使用String.collect

let strip chars = String.collect (fun c -> if Seq.exists((=)c) chars then "" else string c)

strip "xyz" "123x4y5z789" // 12345789

5
由于F#属于.NET平台,我们可以依赖平台库的强大功能。以下是字符剥离任务的简单实现: open System open System.Linq let stripChars chars (text:string) = String.Concat(text.Where(fun c -> not (Set.contains c chars)))) 更新:不幸的是,后来我意识到Enumerable.Except方法生成两个序列的集合差,这意味着stripChars "a" "ababab"只会得到"b"而不是期望的"bbb"
继续在LINQ中实现正确的工作可能会更加冗长:
let stripv1 (stripChars: seq<char>) (text:string) =
    text.Where(fun (c: char) -> not(stripChars.Contains(c))) |> String.Concat    

与等效的F#习惯用法相比,这些可能不值得花费精力:

let stripv2 (stripChars: seq<char>) text =
    text |> Seq.filter(fun c -> not (stripChars.Contains c)) |> String.Concat

因此,一个纯.NET特定的方法是遵循下面评论中Ruben关于String.Split的建议:
let stripv3 (stripChars:string) (text:string) =
    text.Split(stripChars.ToCharArray(), StringSplitOptions.RemoveEmptyEntries) |> String.Concat

+1 或滥用 String.Split :) (在您更新此内容之前,我正要回来发布这个) - Ruben Bartelink

4

尝试使用 Seq.fold

Seq.fold (fun (str: string) chr -> str.Replace(chr, ' ')) "Hello world" stripchars

Fold非常强大。它可以在许多需要重复更改某些内容的情况下使用。

此外,您是否想要实际删除字符而不仅仅是用空格替换它们?如果是这样,您应该使用以下内容:

let stripchars chars str =
  Seq.fold
    (fun (str: string) chr ->
      str.Replace(chr |> Char.ToUpper |> string, "").Replace(chr |> Char.ToLower |> string, ""))
    str chars

此解决方案不区分大小写。

不,我实际上想要删除它们。 - deostroll
稍等,由于某些原因第二个会产生编译错误... 正在尝试修复它。 - Jwosty
完成了,修复好了。希望能对你有所帮助! - Jwosty

0
let doStrip (stripChars: char list) (text:string) =
    text |> String.map (fun c -> if stripChars |> List.contains c then ' ' else c)
    
    
    
let doStrip' (stripChars: string) (text:string) =
    text |> String.map (fun c -> if stripChars.Contains c then ' ' else c)
    

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接