Ste*_*ing 4 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
Run Code Online (Sandbox Code Playgroud)
到目前为止,此方法仅适用于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
Run Code Online (Sandbox Code Playgroud)
我怀疑Ruby的字符串插值和转义是让我困惑的地方.
我如何更改正则表达式以使其在Unix和Windows上都能正常工作?
我实际上并不知道所指的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"]
Run Code Online (Sandbox Code Playgroud)
它不仅与平台无关,而且更易读.
更新
你引起了我的好奇心:
>> 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">
Run Code Online (Sandbox Code Playgroud)
你是对的,\必须双重转义才能使它在正则表达式中工作:一次通过解释器,再次通过正则表达式引擎.(绝对感觉很尴尬.)正则表达式是:
.+[\\/]([^@]+)@(.+)
Run Code Online (Sandbox Code Playgroud)
字符串是:
".+[\\\\/]([^@]+)@(.+)"
Run Code Online (Sandbox Code Playgroud)
正则表达式,对于实际使用可能太脆弱(如何处理没有/或\路径分隔符的路径@或没有或有太多的路径名@?),查找任意数量的字符,单个路径分隔符,任何数量的非@,@,然后任意数量的任何字符.我假设第一个.+将贪婪地消耗尽可能多的字符,以使匹配尽可能向右:
>> evil_path="/foo/bar@baz/blorp/Prefix@invoice.csv"
=> "/foo/bar@baz/blorp/Prefix@invoice.csv"
>> evil_path.match(r)
=> #<MatchData "/foo/bar@baz/blorp/Prefix@invoice.csv" 1:"Prefix" 2:"invoice.csv">
Run Code Online (Sandbox Code Playgroud)
但是,根据输入数据格式错误,它可能会做错了.