Normalize pathnames

Give a path name (absolute or relative) normalize it and return the shortest path representing the given path.

Example

normalize('/abc/def/../') #=> 'abc/'
normalize('/abc/def/../../') #=> ''
normalize('abc/def/../../../') #=> '../'
normalize('/abc/def/../../../') #=> Invalid path name

Solution

  • Use a stack to keep track of the path name
  • Split the pathname by '/'
  • Push into the stack when we see anything other than '.' and '..'
  • For '..' pop from stack
  • When starting with '/' handle empty array appropriately when pop fails
  • When not starting with '/' keep track of '../' seen so we can still report the shortest path

Code

def normalize(pathname)
  return nil if pathname.nil?

  stack = []
  i = 0
  starts_at_root = false

  # If it starts with '/' insert that into stack
  if pathname[0] == '/'
    stack.push('/')
    starts_at_root = true
    i += 1
  end

  # Split and analyze the pathname
  pathname_arr = pathname.split('/')
  while i < pathname_arr.size
    c = pathname_arr[i]

    if c == '.' || c == ''
      # Do nothing
    elsif c == ".."
      if starts_at_root && stack.empty?
        raise StandardError.new('Invalid path provided')
      elsif stack.empty? || stack.last == '..'
        stack.push('..')
      else
        stack.pop
      end
    else

      stack.push(c)
    end
    i += 1
  end

  ## Construct pathname in reverse order
  normalized_pathname = ''

  while !stack.empty?
    normalized_pathname = "#{stack.pop}/#{normalized_pathname}"
  end

  normalized_pathname
end

Time complexity

  • O(n) time where n is the length of the path

results matching ""

    No results matching ""