diff --git a/lib/Filesystem/Path.hs b/lib/Filesystem/Path.hs
--- a/lib/Filesystem/Path.hs
+++ b/lib/Filesystem/Path.hs
@@ -56,9 +56,10 @@
 	) where
 
 import           Prelude hiding (FilePath, concat, null)
+import qualified Prelude as Prelude
 
 import           Data.List (foldl')
-import           Data.Maybe (isNothing)
+import           Data.Maybe (isJust, isNothing)
 import qualified Data.Monoid as M
 import qualified Data.Text as T
 
@@ -87,9 +88,8 @@
 directory p = empty
 	{ pathRoot = pathRoot p
 	, pathDirectories = let
-		starts = map Just [dot, dots]
-		dot' | safeHead (pathDirectories p) `elem` starts = []
-		     | isNothing (pathRoot p) = [dot]
+		dot' | isJust (pathRoot p) = []
+		     | Prelude.null (pathDirectories p) = [dot]
 		     | otherwise = []
 		in dot' ++ pathDirectories p
 	}
@@ -220,6 +220,15 @@
 -- 'stripPrefix' \"\/foo\/\" \"\/bar\/baz.txt\" == Nothing
 -- @
 --
+-- This function operates on logical prefixes, rather than by counting
+-- characters. The prefix @\"\/foo\/bar\/baz\"@ is interpreted the path
+-- @(\"\/foo\/bar\/\", \"baz\")@, and will be stripped accordingly:
+--
+-- @
+-- 'stripPrefix' \"\/foo\/bar\/baz\" \"\/foo\/bar\/baz\/qux\" == Nothing
+-- 'stripPrefix' \"\/foo\/bar\/baz\" \"\/foo\/bar\/baz.txt\" == Just \".txt\"
+-- @
+--
 -- Since: 0.4.1
 stripPrefix :: FilePath -> FilePath -> Maybe FilePath
 stripPrefix x y = if pathRoot x /= pathRoot y
@@ -251,15 +260,25 @@
 	then strip xs ys
 	else Nothing
 
--- | Remove @\".\"@ and @\"..\"@ directories from a path.
+-- | Remove intermediate @\".\"@ and @\"..\"@ directories from a path.
 --
+-- @
+-- 'collapse' \"\/foo\/.\/bar\" == \"\/foo\/bar\"
+-- 'collapse' \"\/foo\/bar\/..\/baz\" == \"\/foo\/baz\"
+-- 'collapse' \"\/foo\/..\/..\/bar\" == \"\/bar\"
+-- 'collapse' \".\/foo\/bar\" == \".\/foo\/baz\"
+-- @
+--
 -- Note that if any of the elements are symbolic links, 'collapse' may change
 -- which file the path resolves to.
 --
 -- Since: 0.2
 collapse :: FilePath -> FilePath
-collapse p = p { pathDirectories = reverse newDirs } where
-	(_, newDirs) = foldl' step (True, []) (pathDirectories p)
+collapse p = p { pathDirectories = newDirs } where
+	newDirs = case pathRoot p of
+		Nothing -> reverse revNewDirs
+		Just _ -> dropWhile (\x -> x == dot || x == dots) (reverse revNewDirs)
+	(_, revNewDirs) = foldl' step (True, []) (pathDirectories p)
 	
 	step (True, acc) c = (False, c:acc)
 	step (_, acc) c | c == dot = (False, acc)
diff --git a/lib/Filesystem/Path/CurrentOS.hs b/lib/Filesystem/Path/CurrentOS.hs
--- a/lib/Filesystem/Path/CurrentOS.hs
+++ b/lib/Filesystem/Path/CurrentOS.hs
@@ -29,6 +29,7 @@
 	-- * Rule&#x2010;specific path properties
 	, valid
 	, splitSearchPath
+	, splitSearchPathString
 	) where
 
 import           Prelude hiding (FilePath)
@@ -117,6 +118,11 @@
 -- of 'FilePath's.
 splitSearchPath :: PLATFORM_PATH_FORMAT -> [F.FilePath]
 splitSearchPath = R.splitSearchPath currentOS
+
+-- | splitSearchPathString is like 'splitSearchPath', but takes a string
+-- encoded in the format used by @System.IO@.
+splitSearchPathString :: String -> [F.FilePath]
+splitSearchPathString = R.splitSearchPathString currentOS
 
 -- | Convert a 'F.FilePath' to a platform&#x2010;specific format, suitable
 -- for use with external OS functions.
diff --git a/lib/Filesystem/Path/Internal.hs b/lib/Filesystem/Path/Internal.hs
--- a/lib/Filesystem/Path/Internal.hs
+++ b/lib/Filesystem/Path/Internal.hs
@@ -113,6 +113,10 @@
 	-- a list of 'FilePath's.
 	, splitSearchPath :: platformFormat -> [FilePath]
 	
+	-- | splitSearchPathString is like 'splitSearchPath', but takes a string
+	-- encoded in the format used by @System.IO@.
+	, splitSearchPathString :: String -> [FilePath]
+	
 	-- | Attempt to convert a 'FilePath' to human&#x2010;readable text.
 	--
 	-- If the path is decoded successfully, the result is a 'Right'
diff --git a/lib/Filesystem/Path/Rules.hs b/lib/Filesystem/Path/Rules.hs
--- a/lib/Filesystem/Path/Rules.hs
+++ b/lib/Filesystem/Path/Rules.hs
@@ -26,6 +26,7 @@
 	-- * Rule&#x2010;specific path properties
 	, valid
 	, splitSearchPath
+	, splitSearchPathString
 	) where
 
 import           Prelude hiding (FilePath, null)
@@ -52,6 +53,7 @@
 	{ rulesName = T.pack "POSIX"
 	, valid = posixValid
 	, splitSearchPath = posixSplitSearch
+	, splitSearchPathString = posixSplitSearch . B8.pack
 	, toText = posixToText
 	, fromText = posixFromText
 	, encode = posixToBytes
@@ -69,6 +71,7 @@
 posix_ghc702 :: Rules B.ByteString
 posix_ghc702 = posix
 	{ rulesName = T.pack "POSIX (GHC 7.2)"
+	, splitSearchPathString = posixSplitSearchString posixFromGhc702String
 	, encodeString = posixToGhc702String
 	, decodeString = posixFromGhc702String
 	}
@@ -82,6 +85,7 @@
 posix_ghc704 :: Rules B.ByteString
 posix_ghc704 = posix
 	{ rulesName = T.pack "POSIX (GHC 7.4)"
+	, splitSearchPathString = posixSplitSearchString posixFromGhc704String
 	, encodeString = posixToGhc704String
 	, decodeString = posixFromGhc704String
 	}
@@ -184,6 +188,10 @@
 posixSplitSearch = map (posixFromBytes . normSearch) . B.split 0x3A where
 	normSearch bytes = if B.null bytes then B8.pack "." else bytes
 
+posixSplitSearchString :: (String -> FilePath) -> String -> [FilePath]
+posixSplitSearchString toPath = map (toPath . normSearch) . splitBy (== ':') where
+	normSearch s = if P.null s then "." else s
+
 -------------------------------------------------------------------------------
 -- Darwin
 -------------------------------------------------------------------------------
@@ -199,6 +207,7 @@
 	{ rulesName = T.pack "Darwin"
 	, valid = posixValid
 	, splitSearchPath = darwinSplitSearch
+	, splitSearchPathString = darwinSplitSearch . TE.decodeUtf8 . B8.pack
 	, toText = Right . darwinToText
 	, fromText = posixFromText
 	, encode = darwinToText
@@ -216,6 +225,7 @@
 darwin_ghc702 :: Rules T.Text
 darwin_ghc702 = darwin
 	{ rulesName = T.pack "Darwin (GHC 7.2)"
+	, splitSearchPathString = darwinSplitSearch . T.pack
 	, encodeString = T.unpack . darwinToText
 	, decodeString = posixFromText . T.pack
 	}
@@ -245,6 +255,7 @@
 	{ rulesName = T.pack "Windows"
 	, valid = winValid
 	, splitSearchPath = winSplit
+	, splitSearchPathString = winSplit . T.pack
 	, toText = Right . winToText
 	, fromText = winFromText
 	, encode = winToText
diff --git a/system-filepath.cabal b/system-filepath.cabal
--- a/system-filepath.cabal
+++ b/system-filepath.cabal
@@ -1,5 +1,5 @@
 name: system-filepath
-version: 0.4.9
+version: 0.4.10
 synopsis: High-level, byte-based file and directory path manipulations
 license: MIT
 license-file: license.txt
@@ -29,7 +29,7 @@
 source-repository this
   type: git
   location: https://john-millikin.com/code/haskell-filesystem/
-  tag: system-filepath_0.4.9
+  tag: system-filepath_0.4.10
 
 library
   ghc-options: -Wall -O2
diff --git a/tests/Tests.hs b/tests/Tests.hs
--- a/tests/Tests.hs
+++ b/tests/Tests.hs
@@ -63,6 +63,7 @@
 		:: Suite)
 	
 	test_SplitSearchPath
+	test_SplitSearchPathString
 	test_Parsing
 	test_EncodeString
 	test_DecodeString
@@ -97,7 +98,7 @@
 	$expect $ equal (directory "../foo") "../"
 	$expect $ equal (directory "../foo/") "../foo/"
 	$expect $ equal (directory "foo") "./"
-	$expect $ equal (directory "foo/bar") "./foo/"
+	$expect $ equal (directory "foo/bar") "foo/"
 
 test_Parent :: Test
 test_Parent = assertions "parent" $ do
@@ -348,6 +349,8 @@
 	$expect $ equal (collapse "parent/foo/baz/../bar") "parent/foo/bar"
 	$expect $ equal (collapse "parent/foo/baz/../../bar") "parent/bar"
 	$expect $ equal (collapse "parent/foo/..") "parent/"
+	$expect $ equal (collapse "/parent/foo/../../../bar") "/bar"
+	$expect $ equal (collapse "/./parent/foo") "/parent/foo"
 
 test_SplitDirectories :: Test
 test_SplitDirectories = assertions "splitDirectories" $ do
@@ -423,13 +426,52 @@
 
 test_SplitSearchPath :: Test
 test_SplitSearchPath = assertions "splitSearchPath" $ do
-	let p x = map (toChar8) (splitSearchPath posix (B8.pack x))
-	let w x = map (toString) (splitSearchPath windows (T.pack x))
+	let p x = map toChar8 (splitSearchPath posix (B8.pack x))
+	let w x = map toString (splitSearchPath windows (T.pack x))
 	
 	$expect $ equal (p "a:b:c") ["a", "b", "c"]
 	$expect $ equal (p "a::b:c") ["a", "./", "b", "c"]
 	$expect $ equal (w "a;b;c") ["a", "b", "c"]
 	$expect $ equal (w "a;;b;c") ["a", "b", "c"]
+
+test_SplitSearchPathString :: Suite
+test_SplitSearchPathString = suite "splitSearchPathString"
+	test_SplitSearchPathString_Posix
+	test_SplitSearchPathString_Posix_Ghc702
+	test_SplitSearchPathString_Posix_Ghc704
+	test_SplitSearchPathString_Darwin
+	test_SplitSearchPathString_Darwin_Ghc702
+	test_SplitSearchPathString_Win32
+
+test_SplitSearchPathString_Posix :: Test
+test_SplitSearchPathString_Posix = assertions "posix" $ do
+	let split x = map (toText posix) (splitSearchPathString posix x)
+	$expect $ equal (split "a::\xC2\xA1\xC2\xA2:\xA1\xA2") [Right "a", Right "./", Right "\xA1\xA2", Left "\xA1\xA2"]
+
+test_SplitSearchPathString_Posix_Ghc702 :: Test
+test_SplitSearchPathString_Posix_Ghc702 = assertions "posix_ghc702" $ do
+	let split x = map (toText posix) (splitSearchPathString posix_ghc702 x)
+	$expect $ equal (split "a::\xA1\xA2:\xEFA1\xEFA2") [Right "a", Right "./", Right "\xA1\xA2", Left "\xA1\xA2"]
+
+test_SplitSearchPathString_Posix_Ghc704 :: Test
+test_SplitSearchPathString_Posix_Ghc704 = assertions "posix_ghc704" $ do
+	let split x = map (toText posix) (splitSearchPathString posix_ghc704 x)
+	$expect $ equal (split "a::\xA1\xA2:\xDCA1\xDCA2") [Right "a", Right "./", Right "\xA1\xA2", Left "\xA1\xA2"]
+
+test_SplitSearchPathString_Darwin :: Test
+test_SplitSearchPathString_Darwin = assertions "darwin" $ do
+	let split x = map (toText darwin) (splitSearchPathString darwin x)
+	$expect $ equal (split "a::\xC2\xA1\xC2\xA2") [Right "a", Right "./", Right "\xA1\xA2"]
+
+test_SplitSearchPathString_Darwin_Ghc702 :: Test
+test_SplitSearchPathString_Darwin_Ghc702 = assertions "darwin_ghc702" $ do
+	let split x = map (toText darwin) (splitSearchPathString darwin_ghc702 x)
+	$expect $ equal (split "a::\xA1\xA2") [Right "a", Right "./", Right "\xA1\xA2"]
+
+test_SplitSearchPathString_Win32 :: Test
+test_SplitSearchPathString_Win32 = assertions "win32" $ do
+	let split x = map (toText windows) (splitSearchPathString windows x)
+	$expect $ equal (split "a;;\xA1\xA2") [Right "a", Right "\xA1\xA2"]
 
 test_EncodeString :: Suite
 test_EncodeString = suite "encodeString"
