Skip to content

Instantly share code, notes, and snippets.

@blandry
Created November 22, 2012 15:11
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save blandry/4131632 to your computer and use it in GitHub Desktop.
Save blandry/4131632 to your computer and use it in GitHub Desktop.
A basic path normalizer I wrote for a job interview.
import re
import unittest
def normalize(path):
## To keep the path pointing to the same place, relative paths should stay
## relative, and absolute paths should stay absolute. I decided to treat the
## ending the same way for consistency
folders = re.split('/', path)
normalized_folders = list()
for folder in folders:
if folder == '..':
try:
if normalized_folders[-1] != '': # this is false if you are trying to exit the root directory
normalized_folders.pop(-1)
except IndexError:
## I assumed wathever the input, we want the output to be a valid
## path pointing to the same place, therefore I do not do change parts of
## the path for which I do not have enough information to normalize. The only
## exception being that exiting the root keeps you in the root.
normalized_folders.append(folder)
elif folder != '.':
normalized_folders.append(folder)
normalized_path = '/'.join(normalized_folders)
return normalized_path
class TestNormalize(unittest.TestCase):
def test_current_dir(self):
cases = [("foo/./bar", "foo/bar"),
("foo/bar/./baz", "foo/bar/baz"),
("./foo/bar", "foo/bar"),]
for input, exp_output in cases:
self.assertEqual(normalize(input), exp_output)
def test_parent_dir(self):
cases = [("foo/bar/../baz", "foo/baz"),
("/foo/bar/..", "/foo"),]
for input, exp_output in cases:
self.assertEqual(normalize(input), exp_output)
def test_hybrid(self):
cases = [("foo/./bar/../baz", "foo/baz"),
("foo/../bar/./baz/..", "bar"),]
for input, exp_output in cases:
self.assertEqual(normalize(input), exp_output)
def test_no_op(self):
cases = [("foo/bar//baz", "foo/bar//baz"),]
for input, exp_output in cases:
self.assertEqual(normalize(input), exp_output)
def test_edge_cases(self):
""" Theses tests do not cover features that were in specs,
rather they test behaviours that I have assumed were desired
(i.e. they are implementation specific). My implementation always
makes sure that the paths stay valid and point to the same place
even if they cannot be normalized.
"""
cases = [("../foo/bar", "../foo/bar"),
("foo/bar/../../../", "../"),
("/./foo/baz", "/foo/baz")]
for input, exp_output in cases:
self.assertEqual(normalize(input), exp_output)
## this is a very special case, trying to exit the root folder.
## Most OS will simply keep you in the root folder, and my
## implementation does the same
input, exp_output = ("/../foo/bar", "/foo/bar")
self.assertEqual(normalize(input), exp_output)
if __name__ == "__main__":
unittest.main()
import java.util.ArrayList;
public class Normalizer {
private ArrayList<int> primes;
public Normalizer() {
primes = new ArrayList<int>();
}
public static String normalize(String path){
String[] folders = path.split("/");
ArrayList<String> normalized_folders = new ArrayList<String>();
for (String folder : folders){
if (folder.equals("..")){
try {
if (!normalized_folders.get(normalized_folders.size()-1).equals("")) {
normalized_folders.remove(normalized_folders.size()-1);
}
}
catch(ArrayIndexOutOfBoundsException e) {
normalized_folders.add(folder);
}
} else if (!folder.equals(".")) {
normalized_folders.add(folder);
}
}
String normalized_path = new String();
for (int i=0; i<=normalized_folders.size()-1; i++) {
normalized_path += normalized_folders.get(i);
if (i!=normalized_folders.size()-1){
normalized_path += "/";
}
}
return normalized_path;
}
public static void main(String[] args){
String input = "foo/./bar";
System.out.println("Input was: "+input);
System.out.println("Output is: "+normalize(input));
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment