【问题标题】:What is the opposite of Regexp.escape?Regexp.escape 的反义词是什么?
【发布时间】:2013-09-30 09:41:35
【问题描述】:

Regexp.escape 的反义词是什么?

> Regexp.escape('A & B')
=> "A\\ &\\ B"
> # do something, to get the next result: (something like Regexp.unescape(A\\ &\\ B))
=> "A & B"

我怎样才能得到原始值?

【问题讨论】:

    标签: ruby regex


    【解决方案1】:
    replaces = Hash.new { |hash,key| key } # simple trick to return key if there is no value in hash
    replaces['t'] = "\t"
    replaces['n'] = "\n"
    replaces['r'] = "\r"
    replaces['f'] = "\f"
    replaces['v'] = "\v"
    
    rx = Regexp.escape('A & B')
    str = rx.gsub(/\\(.)/){ replaces[$1] }
    

    还要确保#puts在irb中输出,因为#inspect默认转义字符。

    基本上转义/引用查找元字符,并预先添加\ 字符(必须对其进行转义以在源代码中进行字符串解释)。但是如果我们从列表中找到任何控制字符:\t\n\r\f\v,然后引用输出\ 字符后跟这个特殊字符转换为ascii。

    更新

    我的解决方案在特殊字符(\n、\t 等)方面存在问题,我在调查rb_reg_quote method 的源代码后对其进行了更新。

    更新 2

    replaces 是哈希,它将转义字符(这就是为什么它在附加到gsub 的块中使用)转换为非转义字符。它按没有转义字符的字符(序列中的第二个字符)进行索引,并搜索未转义的值。唯一定义的值是控制字符,但也附加了default_proc(附加到Hash.new 的块),如果在散列中找不到值,则返回键。所以它是这样工作的:

    1. 对于"n",它返回"\n",对于所有其他转义控制字符都相同,因为它是与键关联的值
    2. 对于"(",它返回"(",因为没有与"("键关联的值,哈希调用#default_proc,它返回键本身

    Regexp.escape 转义的唯一字符是元字符和控制字符,所以我们不必担心字母数字。

    查看http://ruby-doc.org/core-2.0.0/Hash.html#method-i-default_proc 以获取有关#defoult_proc 的文档

    【讨论】:

    • 谢谢,但我得到了双斜线:Regexp.escape('H\B')
    • puts 'H\B'.inspect(irb 这样做是为了返回值)也输出双斜杠。尝试puts 'H\B',然后输入我的解决方案代码的结果
    • 你能解释一下replaces[$1]的作用吗?
    • @user2503775 请参阅我的更新 2 以获得解释。希望它有助于理解这个技巧
    • 谢谢。关于一个斜线 - 我想没有解决方案。因为Regexp.escape('H\B') 给了我"H\\\\B" 所以'我得到了"H\\\\B".gsub(/\\(.)/){ replaces[$1] } 的双斜线。我得到了H\\B 对于这里建议的每一种方式。或者也许你知道如何做到这一点?
    【解决方案2】:

    你也许可以使用这样的东西?

    def unescape(s)
      eval %Q{"#{s}"}
    end
    
    puts unescape('A\\ &\\ B')
    

    感谢this question

    codepad demo

    如果您对正则表达式解决方案没问题,您可以使用这个:

    res = s.gsub(/\\(?!\\)|(\\)\\/, "\\1")
    

    codepad demo

    【讨论】:

    • 我在使用eval的时候总觉得没救了。使用时可以插入恶意代码:unescape('"; puts 42#"')(打印 42,但可能执行删除您的 SO 帐户的脚本)
    • @tessi Mhm,我可以理解。我已经尝试了建议替代方案的答案,但他们要么也使用了eval,要么没有用。 YAML 模块似乎在那里为 OP 工作,但不知何故它不在键盘上;可能是版本...
    • 谢谢,但我不喜欢使用eval ...希望找到另一个选择。
    • @user2503775 我添加了一个.gsub 方法。
    • 如果你还不知道s 是一个完全由你控制的转义正则表达式,eval 似乎非常不安全。试试unescape('";print "hi!')
    【解决方案3】:

    试试这个

    >> r = Regexp.escape("A & B (and * c [ e] + )")
    # => "A\\ &\\ B\\ \\(and\\ \\*\\ c\\ \\[\\ e\\]\\ \\+\\ \\)"
    >> r.gsub("\\(","(").gsub("\\)",")").gsub("\\[","[").gsub("\\]","]").gsub("\\{","{").gsub("\\}","}").gsub("\\.",".").gsub("\\?","?").gsub("\\+","+").gsub("\\*","*").gsub("\\ "," ")
    # => "A & B (and * c [ e] + )"
    

    基本上,这些(, ), [, ], {, }, ., ?, +, * 是正则表达式中的元字符。还有 \ 用作转义字符。

    gsub() 调用链将转义模式替换为对应的实际值。

    我相信有办法干燥这个。

    更新user2503775建议的DRY版本

    >> r.gsub("\\","")
    

    更新

    以下是正则表达式中的特殊字符

        [,],{,},(,),|,-,*,.,\\,?,+,^,$,<space>,#,\t,\f,\v,\n,\r
    

    【讨论】:

    • 对所有类型的特殊字符都适用吗?
    • 我不能说多字节字符。否则,只有对正则表达式引擎具有特殊含义的字符才需要转义。而上面提到的角色是我唯一知道的。
    • r.gsub("\\","") 给了我同样的结果.. 为什么我需要整行?
    • 另外...如果我的字符串中有字符 \ 怎么办?
    • 是的。你是对的r.gsub("\\","") 有效。那是超级干燥。而且我猜您无法在字符串中转义“\”。 Regexp.escape("\") 不返回任何内容。
    【解决方案4】:

    使用正则表达式替换使用\\(?=([\\\*\+\?\|\{\[\(\)\^\$\.\#\ ]))\

    应该给你未转义的字符串,你只需要将\r\n序列替换为CrLf对应的序列。

    "There\ is\ a\ \?\ after\ the\ \(white\)\ car\.\ \r\n\ it\ should\ be\ http://car\.com\?\r\n"
    

    未转义为:

    "There is a ? after the (white) car. \r\n it should be http://car.com?\r\n"
    

    并删除 \r\n 给你:

    There is a ? after the (white) car. 
     it should be http://car.com?
    

    【讨论】:

    • 自己试试:转义 '\? ?产生与 '? 不同的结果\?'
    猜你喜欢
    • 2011-01-04
    • 2014-04-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-07
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多