Created
November 8, 2017 02:59
-
-
Save ExpHP/3f7d8c03be1a45ebe5abd3ad5a517d73 to your computer and use it in GitHub Desktop.
path normalization comparison
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import os | |
import sys | |
alphabet = sys.argv[1] | |
max_depth = int(sys.argv[2]) | |
def gen_strings(alphabet, s, depth): | |
yield s | |
if depth > 0: | |
for ch in alphabet: | |
yield from gen_strings(alphabet, s + ch, depth - 1) | |
for s in gen_strings(alphabet, '', max_depth): | |
print("{:>15} -> {:>15}".format(s, os.path.normpath(s))) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
use std::path::Path; | |
use std::path::PathBuf; | |
use std::path::Component; | |
// https://github.com/rust-lang/rfcs/issues/2208#issuecomment-342679694 | |
fn normalize(p: &Path) -> PathBuf { | |
let mut stack: Vec<Component> = vec![]; | |
// We assume .components() removes redundant consecutive path separators. | |
// Note that .components() also does some normalization of '.' on its own anyways. | |
// This '.' normalization happens to be compatible with the approach below. | |
for component in p.components() { | |
match component { | |
// Drop CurDir components, do not even push onto the stack. | |
Component::CurDir => {}, | |
// For ParentDir components, we need to use the contents of the stack. | |
Component::ParentDir => { | |
// Look at the top element of stack, if any. | |
let top = stack.last().cloned(); | |
match top { | |
// A component is on the stack, need more pattern matching. | |
Some(c) => { | |
match c { | |
// Push the ParentDir on the stack. | |
Component::Prefix(_) => { stack.push(component); }, | |
// The parent of a RootDir is itself, so drop the ParentDir (no-op). | |
Component::RootDir => {}, | |
// A CurDir should never be found on the stack, since they are dropped when seen. | |
Component::CurDir => { panic!("Found an unexpected Component::CurDir"); }, | |
// If a ParentDir is found, it must be due to it piling up at the start of a path. | |
// Push the new ParentDir onto the stack. | |
Component::ParentDir => { stack.push(component); }, | |
// If a Normal is found, pop it off. | |
Component::Normal(_) => { let _ = stack.pop(); } | |
} | |
}, | |
// Stack is empty, so path is empty, just push. | |
None => { stack.push(component); } | |
} | |
}, | |
// All others, simply push onto the stack. | |
_ => { stack.push(component); }, | |
} | |
} | |
// If an empty PathBuf would be return, instead return CurDir ('.'). | |
if stack.is_empty() { | |
return PathBuf::from(Component::CurDir.as_ref()); | |
} | |
let mut norm_path = PathBuf::new(); | |
for item in &stack { | |
norm_path.push(item.as_ref()); | |
} | |
norm_path | |
} | |
fn gen_strings(alphabet: &[String], s: String, depth: u8, f: fn(&str)) { | |
f(&s); | |
if let Some(deeper) = depth.checked_sub(1) { | |
for ch in alphabet { | |
gen_strings(alphabet, s.clone() + ch, deeper, f); | |
} | |
} | |
} | |
fn main() { | |
let mut args = ::std::env::args(); | |
let _ = args.next(); | |
let alphabet = args.next().unwrap().chars().map(|ch| ch.to_string()).collect::<Vec<_>>(); | |
let max_depth = args.next().unwrap().parse().unwrap(); | |
gen_strings(&alphabet[..], Default::default(), max_depth, |s| { | |
let p = Path::new(&s); | |
println!("{:>15} -> {:>15}", p.display(), normalize(&p).display()); | |
}); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment