Just another update
This commit is contained in:
parent
a25938f123
commit
00a190b0a6
6591 changed files with 94363 additions and 23227 deletions
2
Task/Find-common-directory-path/00META.yaml
Normal file
2
Task/Find-common-directory-path/00META.yaml
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
---
|
||||
note: String manipulation
|
||||
|
|
@ -19,18 +19,18 @@ cdp(...)
|
|||
r_last(r, v);
|
||||
|
||||
i = 0;
|
||||
while ((c = character(s, i)) == character(v, i) && c) {
|
||||
while ((c = s[i]) == v[i] && c) {
|
||||
i += 1;
|
||||
}
|
||||
|
||||
if (!c && character(v, i) == '/') {
|
||||
if (!c && v[i] == '/') {
|
||||
} else {
|
||||
while (i && character(s, i - 1) != '/') {
|
||||
while (i && s[i - 1] != '/') {
|
||||
i -= 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (1 < i && character(s, i - 1) == '/') {
|
||||
if (1 < i && s[i - 1] == '/') {
|
||||
i -= 1;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,65 +1,59 @@
|
|||
package main
|
||||
|
||||
import(
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func CommonPrefix(sep string, paths ...string) (string) {
|
||||
func CommonPrefix(sep byte, paths ...string) string {
|
||||
// Handle special cases.
|
||||
switch len(paths) {
|
||||
case 0:
|
||||
return ""
|
||||
case 1:
|
||||
return path.Clean(paths[0])
|
||||
case 0:
|
||||
return ""
|
||||
case 1:
|
||||
return path.Clean(paths[0])
|
||||
}
|
||||
|
||||
// Note, we treat string as []byte, not []rune as is often
|
||||
// done in Go. (And sep as byte, not rune). This is because
|
||||
// most/all supported OS' treat paths as string of non-zero
|
||||
// bytes. A filename may be displayed as a sequence of Unicode
|
||||
// runes (typically encoded as UTF-8) but paths are
|
||||
// not required to be valid UTF-8 or in any normalized form
|
||||
// (e.g. "é" (U+00C9) and "é" (U+0065,U+0301) are different
|
||||
// file names.
|
||||
c := []byte(path.Clean(paths[0]))
|
||||
|
||||
// Ignore the first path since it's already in c.
|
||||
for _, v := range(paths[1:]) {
|
||||
// Clean up each path before testing it.
|
||||
v = path.Clean(v)
|
||||
// We add a trailing sep to handle the case where the
|
||||
// common prefix directory is included in the path list
|
||||
// (e.g. /home/user1, /home/user1/foo, /home/user1/bar).
|
||||
// path.Clean will have cleaned off trailing / separators with
|
||||
// the exception of the root directory, "/" (in which case we
|
||||
// make it "//", but this will get fixed up to "/" bellow).
|
||||
c = append(c, sep)
|
||||
|
||||
// Get the length of the shorter slice.
|
||||
shorter := len(v)
|
||||
if len(v) > len(c) {
|
||||
shorter = len(c)
|
||||
// Ignore the first path since it's already in c
|
||||
for _, v := range paths[1:] {
|
||||
// Clean up each path before testing it
|
||||
v = path.Clean(v) + string(sep)
|
||||
|
||||
// Find the first non-common byte and truncate c
|
||||
if len(v) < len(c) {
|
||||
c = c[:len(v)]
|
||||
}
|
||||
|
||||
// Find the first non-common character and copy up to it into c.
|
||||
for i := 0; i < shorter; i++ {
|
||||
for i := 0; i < len(c); i++ {
|
||||
if v[i] != c[i] {
|
||||
c = c[0:i]
|
||||
c = c[:i]
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Correct for problem caused by prepending the actual common path to the
|
||||
// list of paths searched through.
|
||||
for _, v := range(paths) {
|
||||
if len(v) > len(c) {
|
||||
if strings.HasPrefix(v, string(c)) {
|
||||
if len(v) > len(c) + len(sep) {
|
||||
if v[len(c):len(c)+len(sep)] == sep {
|
||||
c = append(c, []byte(sep)...)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Remove trailing non-seperator characters.
|
||||
for i := len(c)-1; i >= 0; i-- {
|
||||
if i + len(sep) > len(c) {
|
||||
continue
|
||||
}
|
||||
|
||||
if string(c[i:i+len(sep)]) == sep {
|
||||
c = c[0:i]
|
||||
// Remove trailing non-separator characters and the final separator
|
||||
for i := len(c) - 1; i >= 0; i-- {
|
||||
if c[i] == sep {
|
||||
c = c[:i]
|
||||
break
|
||||
}
|
||||
}
|
||||
|
|
@ -68,10 +62,18 @@ func CommonPrefix(sep string, paths ...string) (string) {
|
|||
}
|
||||
|
||||
func main() {
|
||||
c := CommonPrefix("/",
|
||||
c := CommonPrefix(os.PathSeparator,
|
||||
//"/home/user1/tmp",
|
||||
"/home/user1/tmp/coverage/test",
|
||||
"/home/user1/tmp/covert/operator",
|
||||
"/home/user1/tmp/coven/members",
|
||||
"/home//user1/tmp/coventry",
|
||||
"/home/user1/././tmp/covertly/foo",
|
||||
"/home/bob/../user1/tmp/coved/bar",
|
||||
)
|
||||
fmt.Printf("%v\n", c)
|
||||
if c == "" {
|
||||
fmt.Println("No common path")
|
||||
} else {
|
||||
fmt.Println("Common path:", c)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,6 @@
|
|||
sub common_prefix {
|
||||
my $sep = shift;
|
||||
my $paths = join "\0", map { $_.$sep } @_;
|
||||
$paths =~ /^ ( [^\0]* ) $sep [^\0]* (?: \0 \1 $sep [^\0]* )* $/sx;
|
||||
return $1;
|
||||
}
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
use List::Util qw(first);
|
||||
|
||||
sub common_prefix {
|
||||
my ($sep, @paths) = @_;
|
||||
my %prefixes;
|
||||
|
||||
foreach (@paths) {
|
||||
do { ++$prefixes{$_} } while s/$sep [^$sep]* $//g
|
||||
}
|
||||
|
||||
return first { $prefixes{$_} == @paths } reverse sort keys %prefixes;
|
||||
}
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
my @paths = qw(/home/user1/tmp/coverage/test
|
||||
/home/user1/tmp/covert/operator
|
||||
/home/user1/tmp/coven/members);
|
||||
print common_prefix('/', @paths), "\n";
|
||||
|
|
@ -1,19 +0,0 @@
|
|||
use List::Util qw(max reduce);
|
||||
sub compath {
|
||||
my ($sep, @paths, %hash) = @_;
|
||||
# Tokenize and tally subpaths
|
||||
foreach (@paths) {
|
||||
my @tok = split $sep, substr($_,1);
|
||||
++$hash{join $sep, @tok[0..$_]} for (0..$#tok); }
|
||||
# Return max length subpath or null
|
||||
my $max = max values %hash;
|
||||
return '' unless $max == @paths;
|
||||
my @res = grep {$hash{$_} == $max} keys %hash;
|
||||
return $sep . reduce { length $a > length $b ? $a : $b } @res;
|
||||
}
|
||||
|
||||
# Test and display
|
||||
my @paths = qw(/home/user1/tmp/coverage/test
|
||||
/home/user1/tmp/covert/operator
|
||||
/home/user1/tmp/coven/members);
|
||||
print compath('/', @paths), "\n";
|
||||
|
|
@ -3,4 +3,4 @@ require 'abbrev'
|
|||
dirs = %w( /home/user1/tmp/coverage/test /home/user1/tmp/covert/operator /home/user1/tmp/coven/members )
|
||||
|
||||
common_prefix = dirs.abbrev.keys.min_by {|key| key.length}.chop # => "/home/user1/tmp/cove"
|
||||
common_directory = common_prefix.sub(%r{/[^/]*$}, '') # => "/home/user1/tmp"
|
||||
common_directory = common_prefix.sub(%r{/[^/]*$}, '') # => "/home/user1/tmp"
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
separator = '/'
|
||||
paths = dirs.collect {|dir| dir.split(separator)}
|
||||
uncommon_idx = paths.transpose.each_with_index.find {|dirnames, idx| dirnames.uniq.length > 1}.last
|
||||
common_directory = paths[0][0 ... uncommon_idx].join(separator) # => "/home/user1/tmp"
|
||||
uncommon_idx = paths[0].zip(*paths[1..-1]).index {|dirnames| dirnames.uniq.length > 1}
|
||||
uncommon_idx = paths[0].length unless uncommon_idx # if uncommon_idx==nil
|
||||
common_directory = paths[0][0...uncommon_idx].join(separator) # => "/home/user1/tmp"
|
||||
|
|
|
|||
|
|
@ -0,0 +1,17 @@
|
|||
object FindCommonDirectoryPath extends App {
|
||||
def commonPath(paths: List[String]): String = {
|
||||
def common(a: List[String], b: List[String]): List[String] = (a, b) match {
|
||||
case (a :: as, b :: bs) if a equals b => a :: common(as, bs)
|
||||
case _ => Nil
|
||||
}
|
||||
if (paths.length < 2) paths.headOption.getOrElse("")
|
||||
else paths.map(_.split("/").toList).reduceLeft(common).mkString("/")
|
||||
}
|
||||
|
||||
val test = List(
|
||||
"/home/user1/tmp/coverage/test",
|
||||
"/home/user1/tmp/covert/operator",
|
||||
"/home/user1/tmp/coven/members"
|
||||
)
|
||||
println(commonPath(test))
|
||||
}
|
||||
|
|
@ -0,0 +1,50 @@
|
|||
object FindCommonDirectoryPathRelative extends App {
|
||||
def commonPath(paths: List[String]): String = {
|
||||
val SEP = "/"
|
||||
val BOUNDARY_REGEX = s"(?=[$SEP])(?<=[^$SEP])|(?=[^$SEP])(?<=[$SEP])"
|
||||
def common(a: List[String], b: List[String]): List[String] = (a, b) match {
|
||||
case (a :: as, b :: bs) if a equals b => a :: common(as, bs)
|
||||
case _ => Nil
|
||||
}
|
||||
if (paths.length < 2) paths.headOption.getOrElse("")
|
||||
else paths.map(_.split(BOUNDARY_REGEX).toList).reduceLeft(common).mkString
|
||||
}
|
||||
|
||||
val test = List(
|
||||
"/home/user1/tmp/coverage/test",
|
||||
"/home/user1/tmp/covert/operator",
|
||||
"/home/user1/tmp/coven/members"
|
||||
)
|
||||
println(commonPath(test).replaceAll("/$", ""))
|
||||
|
||||
// test cases
|
||||
assert(commonPath(test.take(1)) == test.head)
|
||||
assert(commonPath(Nil) == "")
|
||||
assert(commonPath(List("")) == "")
|
||||
assert(commonPath(List("/")) == "/")
|
||||
assert(commonPath(List("/", "")) == "")
|
||||
assert(commonPath(List("/", "/a")) == "/")
|
||||
assert(commonPath(List("/a", "/b")) == "/")
|
||||
assert(commonPath(List("/a", "/a")) == "/a")
|
||||
assert(commonPath(List("/a/a", "/b")) == "/")
|
||||
assert(commonPath(List("/a/a", "/b")) == "/")
|
||||
assert(commonPath(List("/a/a", "/a")) == "/a")
|
||||
assert(commonPath(List("/a/a", "/a/b")) == "/a/")
|
||||
assert(commonPath(List("/a/b", "/a/b")) == "/a/b")
|
||||
assert(commonPath(List("a", "/a")) == "")
|
||||
assert(commonPath(List("a/a", "/a")) == "")
|
||||
assert(commonPath(List("a/a", "/b")) == "")
|
||||
assert(commonPath(List("a", "a")) == "a")
|
||||
assert(commonPath(List("a/a", "b")) == "")
|
||||
assert(commonPath(List("a/a", "b")) == "")
|
||||
assert(commonPath(List("a/a", "a")) == "a")
|
||||
assert(commonPath(List("a/a", "a/b")) == "a/")
|
||||
assert(commonPath(List("a/b", "a/b")) == "a/b")
|
||||
assert(commonPath(List("/a/", "/b/")) == "/")
|
||||
assert(commonPath(List("/a/", "/a/")) == "/a/")
|
||||
assert(commonPath(List("/a/a/", "/b/")) == "/")
|
||||
assert(commonPath(List("/a/a/", "/b/")) == "/")
|
||||
assert(commonPath(List("/a/a/", "/a/")) == "/a/")
|
||||
assert(commonPath(List("/a/a/", "/a/b/")) == "/a/")
|
||||
assert(commonPath(List("/a/b/", "/a/b/")) == "/a/b/")
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue