比较字符串结构

时间:2015-07-07 13:24:06

标签: string algorithm f#

我正在研究F#中的一个项目,我希望能够找到一种方法来识别两个字符串是否具有相同的结构。我知道有些算法(比如Levenshtein Distance)提供了类似字符串在内容方面的近似值,但我更感兴趣的是比较字符串的实际结构。在结构与内容方面,请考虑以下示例:

&#34 07 /二千零十五​​分之十四"和" 11/06 / 1999"根据像Levenshtein Distance这样的算法,它将被归类为非常不同的。但是,它们在结构上都是相同的(日期)。

此外,一组以三个字母开头的字符串(" USA123"," USA456"," USA789")理想情况下会识别为与其他六个字符串不同的结构,如" 123123"或" USAUSA"。

我意识到这很可能是一个相当复杂的解决方案,但我想知道是否存在这样的事情并且我错过了,或者是否有人对此事有任何想法/想法。

3 个答案:

答案 0 :(得分:1)

虽然不是一个完整的答案,但你可以做一些非常基本的测试来捕捉上面给出的例子:

  1. 准备一系列字符。我的意思是将大写,小写,数字,分隔符等分开。
  2. 比较两个字符串时,请检查同一个地方的字符是否属于同一个组。这将使19/07/198325/12/1853相似,但19/07/198325/12/185A不相似。与USAUSAUSA123相同。
  3. 使识别更准确是一个创建越来越精确的群体的问题......

答案 1 :(得分:0)

如上所述,您需要对角色进行分类。完成后,比较两组字符分类很容易。这是一个F#样本:

let areStructurallyEqual (a, b) = 
    let charClass= function 
        | c when Char.IsLetter(c) -> 'L'
        | c when Char.IsDigit(c) -> 'D'
        | c when Char.IsSymbol(c) -> 'S'
        | c when Char.IsWhiteSpace(c) -> ' '
        | _ -> '_'

    let structureString i = new String (i |> Seq.map charClass |> Seq.toArray)
    structureString a = structureString b

[( "07/14/2015", "11/06/1999" ); ("USA123", "USA456"); ("123123", "USA123");]
    |> Seq.map areStructurallyEqual

// returns [ True; True; False; ]

答案 2 :(得分:0)

这个问题看起来有点主观,因为它邀请基于意见的答案,其中许多可能同样好。让我尝试回答,但同样,它可能会或可能不会对您的特定目的有益。

如果您的应用程序只是一个用于自学的小项目,那么一系列简单的正则表达式可能没问题,前提是您将它​​们合并为一系列尝试。

如果项目很大并且应该以某种方式增长(例如,可能会出现新的字符串格式),那么我会推荐一些解析器组合库,例如FParsec,它非常适合解析复杂字符串。这里还有一个标记。

使用组合器,您可以开发各自的解析器并将它们组合在一起,但需要这样:

// Domain specifics
type MyData =
    | Date of DateTime
    | CountryCode of (string * code)
    | Error

// Parsers
let parseDate: Parser<MyData> =
    ... // something returning MyData.Date(x)
let parseCountryCode: Parser<MyData> =
    ... // something returning MyData.CountryCode(x, y)

// a simple combined parser
let parseRoot: Parser<MyData> =
    [parseDate; parseCountryCode; parseSomethingElse;]
    |> choice

let myCode stringTroParse =
    let foundValue =
        match runParserOnString parseRoot myUserState myStreamName stringTroParse with
        | Success(result, _, _) -> result
        | Failure(_, _, _)      -> MyData.Error
    // here you can work with foundValue as usual

使用这种方法,比较几个字符串的结构变得微不足道:它们被解析为MyData区分联合的不同情况。

如果偶尔需要新的解析器,您可以在顶部添加另一个函数并将其引用添加到parseRoot正文中。此外,如果需要更复杂的东西(例如,您需要一些防护规则或不同的方法来组合解析器),则可以使用该库。