Ruby Regex将匹配Unix和Windows文件路径

时间:2011-07-03 09:03:00

标签: ruby regex filepath

以下实例方法接受文件路径并返回文件的前缀(分隔符前面的部分):

  
@separator = "@"

def table_name path
  regex = Regexp.new("\/[^\/]+#{@separator}")
  path.match(regex)[0].gsub(/^.|.$/,'').downcase.to_sym
end

table_name "bla/bla/bla/Prefix@invoice.csv"
# => :prefix

到目前为止,此方法仅适用于Unix。为了使它在Windows上运行,我还需要捕获反斜杠(\)。不幸的是,那是我被困的时候:

@separator = "@"

def table_name path
  regex = Regexp.new("(\/|\\)[^\/\\]+#{@separator}")
  path.match(regex)[0].gsub(/^.|.$/,'').downcase.to_sym
end

table_name("bla/bla/bla/Prefix@invoice.csv")
# RegexpError: premature end of char-class: /(\/|\)[^\/\]+@/

# Target result:
table_name("bla/bla/bla/Prefix@invoice.csv")
# => :prefix
table_name("bla\bla\bla\Prefix@invoice.csv")
# => :prefix

我怀疑Ruby的字符串插值和转义是让我困惑的地方。

如何更改正则表达式以使其在Unix和Windows上都能正常工作?

1 个答案:

答案 0 :(得分:6)

我实际上并不知道bla/bla/bla/Prefix@invoice.csv指的是什么;是bla/bla/bla/bla所有目录,文件名是Prefix@invoice.csv

假设我已正确理解您的文件名,我建议使用File.split()

irb> (path, name) = File.split("bla/bla/bla/Prefix@invoice.csv")
=> ["bla/bla/bla", "Prefix@invoice.csv"]
irb> (prefix, postfix) = name.split("@")
=> ["Prefix", "invoice.csv"]

它不仅与平台无关,而且更易读。

<强>更新

你引起了我的好奇心:

>> wpath="blah\\blah\\blah\\Prefix@invoice.csv"
=> "blah\\blah\\blah\\Prefix@invoice.csv"
>> upath="bla/bla/bla/Prefix@invoice.csv"
=> "bla/bla/bla/Prefix@invoice.csv"
>> r=Regexp.new(".+[\\\\/]([^@]+)@(.+)")
=> /.+[\\\/]([^@]+)@(.+)/
>> wpath.match(r)
=> #<MatchData "blah\\blah\\blah\\Prefix@invoice.csv" 1:"Prefix" 2:"invoice.csv">
>> upath.match(r)
=> #<MatchData "bla/bla/bla/Prefix@invoice.csv" 1:"Prefix" 2:"invoice.csv">

你是对的,\必须双重转义才能使它在正则表达式中运行:一次通过解释器,再次通过正则表达式引擎。 (绝对感觉很尴尬。)正则表达式是:

.+[\\/]([^@]+)@(.+)

字符串是:

".+[\\\\/]([^@]+)@(.+)"

正则表达式,对于实际使用可能太脆弱(如何处理没有/\路径分隔符的路径或没有@的路径名或具有太多{{{ 1}}?),查找任意数量的字符,单个路径分隔符,任何数量的非@,@,然后任意数量的任何字符。我假设第一个@将贪婪地消耗尽可能多的字符,以使匹配尽可能远离正确

.+

但是根据输入数据格式错误,它可能会做错了。