如何判断一条路径是否是另一条路径的祖先?

时间:2014-11-12 02:39:38

标签: ruby filesystems

我需要检查路径字符串a表示的目录是否是路径字符串b表示的目录或文件的祖先(或者是),并且两个路径实际存在

我天真的实现看起来像:

b.starts_with?(a) && File.exist?(b)

示例失败了:

# should be false
a = '/foo/bar'
b = '/foo/bartholomew/monkey'

# should be true
a = '/foo/bar'
b = '/foo/../foo/bar/monkey

我可以通过迭代文件b的父项并检查是否有任何匹配a来完成这项工作,但是公共库中是否有任何方法可以使它更简单,就像Python中的这个解决方案一样? - How can I tell if a file is a descendant of a given directory?

3 个答案:

答案 0 :(得分:4)

不要对字符串进行操作,而是让目录列出并检查是否以另一个开头

def is_descendant?(a, b)
  a_list = File.expand_path(a).split('/')
  b_list = File.expand_path(b).split('/')

  b_list[0..a_list.size-1] == a_list
end

is_descendant?('/foo/bar', '/foo/bartholomew/monkey') #=> false
is_descendant?('/foo/bar', '/foo/../foo/bar/monkey') #=> true

File.expand似乎是Ruby相当于Python os.path.realpath

答案 1 :(得分:0)

这似乎适用于您的测试用例:

def descendant?(a, b)
  [a, b].each { |x| x.replace File.expand_path(x) }
  !b.split('/').zip(a.split('/')).any? { |x, y| y != nil && x != y }
end

descendant? '/foo/bar', '/foo/bartholomew/monkey' # => false
descendant? '/foo/bar', '/foo/../foo/bar/monkey'  # => true

答案 2 :(得分:0)

我实现了这个,以便函数检查其中一个字符串是否是另一个字符串的祖先。在重新阅读你的问题时,这可能不是你想要的,但哦,好吧......

def path_components(path_string)
  File.expand_path(path_string).split('/')
end

# Check if either x_str or y_str is an ancestor of the other.
def is_one_ancestor?(x_str, y_str)
  x_parts = path_components(x_str)
  y_parts = path_components(y_str)

  shorter_length = [x_parts, y_parts].map(&:length).min

  # Find the length of the common prefix of the two paths.
  common_path_length = x_parts.zip(y_parts).take_while do |x,y|
    x == y
  end.length

  # one is an ancestor of the other if the common path length
  # is equal to the length of the shorter path
  common_path_length == shorter_length
end

a = '/foo/bar'
b = '/foo/bartholomew/monkey'
puts is_one_ancestor?(a,b) # false
puts is_one_ancestor?(b,a) # false

c = '/foo/bar'
d = '/foo/../foo/bar/monkey'
puts is_one_ancestor?(c,d) # true
puts is_one_ancestor?(d,c) # true