以下实例方法接受文件路径并返回文件的前缀(分隔符前面的部分):
@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上都能正常工作?
答案 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}}?),查找任意数量的字符,单个路径分隔符,任何数量的非@,@,然后任意数量的任何字符。我假设第一个@
将贪婪地消耗尽可能多的字符,以使匹配尽可能远离正确:
.+
但是根据输入数据格式错误,它可能会做错了。