【问题标题】:Ruby Regex to Match Both Unix And Windows File PathsRuby Regex 匹配 Unix 和 Windows 文件路径
【发布时间】:2011-07-03 09:02:59
【问题描述】:

以下实例方法采用文件路径并返回文件的前缀(分隔符之前的部分):

@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 上运行?

【问题讨论】:

  • 我认为有一个 Ruby 常量可以处理这个问题 - 在 Unix 中是 /,在 Windows 中是 ``。

标签: ruby regex filepath


【解决方案1】:

我实际上不知道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">

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

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

字符串是:

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

正则表达式对于实际使用可能太脆弱(它如何处理没有/ 或\ 路径分隔符的路径或没有@ 或太多@ 的路径名?),寻找任意数量的字符、单个路径分隔符、任意数量的非@、@,然后是任意数量的任意字符。我假设第一个.+ 会贪婪地消耗尽可能多的字符,以使匹配尽可能靠近 right:

>> 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">

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

【讨论】:

  • 感谢您提供这个优雅的解决方案!由于我对 Ruby 的类库还不够熟悉,所以我能想到的就是使用正则表达式。但是,我仍然想知道如何使我的方法奏效。我读到了 Ruby 中的双重转义,但我不确定这是否适用于此。
  • 我必须知道,所以我去尝试了。 :) 还不错,但我不认为它是立即清晰的。
  • 我很高兴你必须知道 :-) 即使在这里使用正则表达式可能不是最好的解决方案,我通过尝试你的代码示例学到了很多关于如何在 Ruby 中处理正则表达式.非常感谢你!附带说明一下,以下答案还添加了更多信息:Backslash and captured group within Ruby regular expression。
猜你喜欢
  • 2012-01-27
  • 2020-05-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-10-16
  • 2012-03-16
  • 2022-12-16
  • 1970-01-01
相关资源
最近更新 更多