草庐IT

regex - Swift 覆盖 + 多种类型和长表达式

coder 2023-09-10 原文

我正在尝试创建一个方便的类来快速构建复杂的正则表达式。这部分按预期工作:

/**
A RegexAtom contains a regular expression pattern, or fragment of a pattern. Capture groups can be named with the groupNames array.
RegexAtom does no syntax checking on the pattern. Typical usage is to define several fragments of a regex pattern, and then combine
them using finalPattern = foo + bar + soom
*/
public class RegexAtom{
    var regex: String = ""
    var groupNames: [String] = []
    public init(regex: String, groupNames:[String]){
        self.regex = regex
        self.groupNames = groupNames
    }
    public init(regex: String){
        self.regex = regex
        self.groupNames = []
    }

}
func +(left: RegexAtom, right: RegexAtom) -> RegexAtom{
    var foo = RegexAtom(regex: left.regex,groupNames: left.groupNames)
    foo.regex += right.regex
    foo.groupNames.extend(right.groupNames)
    return foo
}

我可以使用 + 添加复杂的 RegexAtoms,它符合要求并且运行得很好。

问题来自于希望能够更紧凑地处理文字字符串,就像在 PyParsing 中所做的那样(我想念 PyParsing :( )

这个函数的工作原理:

func +(left:RegexAtom, right: String)->RegexAtom{
var foo = RegexAtom(regex: left.regex,groupNames: left.groupNames)
foo.regex.extend(right)
return foo

但是如果我尝试像这样构建一个复杂的正则表达式

let WS: RegexAtom = RegexAtom(regex:"\\s*")
let tableHeader1 = RegexAtom(regex: "Date") + WS + "Flight" + WS + "Depart" + WS + "Arrive" + WS + "Eq" + WS + "Blk" + WS + "Grnd" + WS + "Blk" + WS + "Duty" + WS + "Cred"

编译错误:

“表达式太复杂,无法在合理的时间内解决。考虑将表达式分解为不同的子表达式。”

但这工作正常:

let tableHeader1 = RegexAtom(regex: "Date") + WS + "Flight"

较长的表达式对我来说并不算长,但我在 Xcode 或 swift 方面的经验很少。

有什么建议吗?

最佳答案

这里有一些因素结合在一起导致了您的问题。

首先,最好避免这种事情:

func +(left: RegexAtom, right: String) -> RegexAtom { ... }

有两个原因。这种静默类型强制在 Swift 中有点不受欢迎。例如,没有标准库运算符允许您将整数与 float 相加。人们倾向于假设 + 是可交换的(即 a + b == b + a),因此您需要定义一个版本,其中左边是字符串,右边是正则表达式。

第二个问题是 "thing" 不是 String。它是一个字符串文字,可以创建任何实现 StringLiteralConvertible 的类型。默认类型是 String,但也可以是 CharacterStaticString 或任何其他自定义类型。

Swift 的类型推断引擎非常灵活——它会努力为您放入表达式中的所有类型找到可能的匹配项。然后,如果有多个匹配项,它会尝试根据一系列优先规则选择最佳匹配项。但在大表达式中,可能性太多了,调查所有这些都是组合的噩梦,所以它就放弃了。

想想你的简单例子。 Swift 选择的解释是这样的:

let tableHeader1 = (RegexAtom(regex: "Date") + WS) + ("Flight" as String)

这是因为 + 是左关联的,字符串文字默认为 String。但它还必须考虑其他一些替代方案:

// this will have been considered and rejected, because there's no operator
// that adds characters to regexes
let tableHeader1 = (RegexAtom(regex: "Date") + WS) + ("Flight" as Character)

// this will compile, but the other version is preferred because + is left-
// associative.  But if the first version resulted in an expression that
// didn't compile (say a regex plus a regex equals an integer), it would
// fall back to this possibility
let tableHeader1 = RegexAtom(regex: "Date") + (WS + ("Flight" as String))

现在,想象一下您超长的加号表达式所暗示的可能性的组合爆炸。

作为替代方案,您可以考虑放弃 +(RegexAtom,String) 运算符,而是让 RegexAtom 符合 StringLiteralConvertible:

extension RegexAtom: StringLiteralConvertible {
    public init(stringLiteral: String) {
        self.init(regex: stringLiteral)
    }
    public init(extendedGraphemeClusterLiteral: String) {
        self.init(regex: extendedGraphemeClusterLiteral)
    }
    public init(unicodeScalarLiteral: String) {
        self.init(regex: unicodeScalarLiteral)
    }
}

如果您这样做,看起来您的复杂表达式可以编译 OK。

关于regex - Swift 覆盖 + 多种类型和长表达式,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29306221/

有关regex - Swift 覆盖 + 多种类型和长表达式的更多相关文章

  1. ruby-on-rails - 在混合/模块中覆盖模型的属性访问器 - 2

    我有一个包含模块的模型。我想在模块中覆盖模型的访问器方法。例如:classBlah这显然行不通。有什么想法可以实现吗? 最佳答案 您的代码看起来是正确的。我们正在毫无困难地使用这个确切的模式。如果我没记错的话,Rails使用#method_missing作为属性setter,因此您的模块将优先,阻止ActiveRecord的setter。如果您正在使用ActiveSupport::Concern(参见thisblogpost),那么您的实例方法需要进入一个特殊的模块:classBlah

  2. ruby-on-rails - 如何优雅地重启 thin + nginx? - 2

    我的瘦服务器配置了nginx,我的ROR应用程序正在它们上运行。在我发布代码更新时运行thinrestart会给我的应用程序带来一些停机时间。我试图弄清楚如何优雅地重启正在运行的Thin实例,但找不到好的解决方案。有没有人能做到这一点? 最佳答案 #Restartjustthethinserverdescribedbythatconfigsudothin-C/etc/thin/mysite.ymlrestartNginx将继续运行并代理请求。如果您将Nginx设置为使用多个上游服务器,例如server{listen80;server

  3. ruby - 无法覆盖 irb 中的 to_s - 2

    我在pry中定义了一个函数:to_s,但我无法调用它。这个方法去哪里了,怎么调用?pry(main)>defto_spry(main)*'hello'pry(main)*endpry(main)>to_s=>"main"我的ruby版本是2.1.2看了一些答案和搜索后,我认为我得到了正确的答案:这个方法用在什么地方?在irb或pry中定义方法时,会转到Object.instance_methods[1]pry(main)>defto_s[1]pry(main)*'hello'[1]pry(main)*end=>:to_s[2]pry(main)>defhello[2]pry(main)

  4. ruby - 覆盖相似的方法,更短的语法 - 2

    在Ruby类中,我重写了三个方法,并且在每个方法中,我基本上做同样的事情:classExampleClassdefconfirmation_required?is_allowed&&superenddefpostpone_email_change?is_allowed&&superenddefreconfirmation_required?is_allowed&&superendend有更简洁的语法吗?如何缩短代码? 最佳答案 如何使用别名?classExampleClassdefconfirmation_required?is_a

  5. ruby - 是否可以覆盖 gemfile 进行本地开发? - 2

    我们的git存储库中目前有一个Gemfile。但是,有一个gem我只在我的环境中本地使用(我的团队不使用它)。为了使用它,我必须将它添加到我们的Gemfile中,但每次我checkout到我们的master/dev主分支时,由于与跟踪的gemfile冲突,我必须删除它。我想要的是类似Gemfile.local的东西,它将继承从Gemfile导入的gems,但也允许在那里导入新的gems以供使用只有我的机器。此文件将在.gitignore中被忽略。这可能吗? 最佳答案 设置BUNDLE_GEMFILE环境变量:BUNDLE_GEMFI

  6. ruby - nanoc 和多种布局 - 2

    是否可以为特定(或所有)项目使用多个布局?例如,我有几个项目,我想对其应用两种不同的布局。一个是绿色的,一个是蓝色的(但是)。我想将它们编译到我的输出目录中的两个不同文件夹中(例如v1和v2)。我一直在玩弄规则和编译block,但我不知道这是怎么回事。因为,每个项目在编译过程中只编译一次,我不能告诉nanoc第一次用layout1编译,第二次用layout2编译。我试过这样的东西,但它导致输出文件损坏。compile'*'doifitem.binary?#don’tfilterbinaryitemselsefilter:erblayout'layout1'layout'layout2'

  7. ruby - 使用 `+=` 和 `send` 方法 - 2

    如何将send与+=一起使用?a=20;a.send"+=",10undefinedmethod`+='for20:Fixnuma=20;a+=10=>30 最佳答案 恐怕你不能。+=不是方法,而是语法糖。参见http://www.ruby-doc.org/docs/ProgrammingRuby/html/tut_expressions.html它说Incommonwithmanyotherlanguages,Rubyhasasyntacticshortcut:a=a+2maybewrittenasa+=2.你能做的最好的事情是:

  8. ruby - 如何计算 Liquid 中的变量 +1 - 2

    我对如何计算通过{%assignvar=0%}赋值的变量加一完全感到困惑。这应该是最简单的任务。到目前为止,这是我尝试过的:{%assignamount=0%}{%forvariantinproduct.variants%}{%assignamount=amount+1%}{%endfor%}Amount:{{amount}}结果总是0。也许我忽略了一些明显的东西。也许有更好的方法。我想要存档的只是获取运行的迭代次数。 最佳答案 因为{{incrementamount}}将输出您的变量值并且不会影响{%assign%}定义的变量,我

  9. Ruby - 如何处理子类意外覆盖父类(super class)私有(private)字段的问题? - 2

    假设您编写了一个类Sup,我决定将其扩展为SubSup。我不仅需要了解你发布的接口(interface),还需要了解你的私有(private)字段。见证这次失败:classSupdefinitialize@privateField="fromsup"enddefgetXreturn@privateFieldendendclassSub问题是,解决这个问题的正确方法是什么?看起来子类应该能够使用它想要的任何字段而不会弄乱父类(superclass)。编辑:equivalentexampleinJava返回"fromSup",这也是它应该产生的答案。 最佳答案

  10. ruby - 解释为局部变量会覆盖方法名称吗? - 2

    如thisquestion,当在其自己的赋值中使用未定义的局部变量时,它的计算结果为nil。x=x#=>nil但是当局部变量的名称与现有的方法名称冲突时,就比较棘手了。为什么下面的最后一个示例返回nil?{}.instance_eval{a=keys}#=>[]{}.instance_eval{keys=self.keys}#=>[]{}.instance_eval{keys=keys}#=>nil 最佳答案 在Ruby中,因为可以在没有显式接收器和括号的情况下调用方法,所以在局部变量引用和无接收器无参数方法调用之间存在语法歧义:f

随机推荐