Ir al contenido principal

Extensión de un fichero


La extensión de un fichero es la palabra a continuación del último punto en el nombre del fichero. Por ejemplo, la extensión de "documento.txt" es "txt"

Definir la función

extension :: String -> String

tal que (extension cs) es la extensión del fichero cs. Por ejemplo,

extension "ejercicio.hs"       ==  "hs"
extension "documento.txt"      ==  "txt"
extension "documento.txt.pdf"  ==  "pdf"
extension "resumen"            ==  ""

Soluciones

import Test.Hspec (Spec, describe, hspec, it, shouldBe)
import Test.QuickCheck

-- 1ª solución
-- ===========

extension1 :: String -> String
extension1 cs | '.' `elem` cs = reverse (aux (reverse cs))
              | otherwise     = ""
  where aux []      = []
        aux ('.':_) = []
        aux (d:ds)  = d : aux ds

-- 2ª solución
-- ===========

extension2 :: String -> String
extension2 cs
  | '.' `notElem` cs = ""
  | otherwise        = reverse (takeWhile (/= '.') (reverse cs))

-- 3ª solución
-- ===========

extension3 :: String -> String
extension3 cs
  | '.' `notElem` cs = ""
  | otherwise        = drop n cs
  where n = last [y | ('.',y) <- zip cs [1..]]

-- 4ª solución
-- ===========

extension4 :: String -> String
extension4 cs =
  case break (== '.') (reverse cs) of
    (_, [])     -> ""
    (ds, _) -> reverse ds

-- Verificación
-- ============

verifica :: IO ()
verifica = hspec spec

specG :: (String -> String) -> Spec
specG extension = do
  it "e1" $
    extension "ejercicio.hs"      `shouldBe` "hs"
  it "e2" $
    extension "documento.txt"     `shouldBe` "txt"
  it "e3" $
    extension "documento.txt.pdf" `shouldBe` "pdf"
  it "e4" $
    extension "resumen"           `shouldBe` ""

spec :: Spec
spec = do
  describe "def. 1" $ specG extension1
  describe "def. 2" $ specG extension2
  describe "def. 3" $ specG extension3
  describe "def. 4" $ specG extension4

-- La verificación es
--    λ> verifica
--    16 examples, 0 failures

-- Comprobación de equivalencia
-- ============================

-- Generador de cadenas. Por ejemplo,
--    λ> generate genCadena
--    "e63.bd8"
--    λ> generate genCadena
--    "yifm5fp9.ywy"
genCadena :: Gen String
genCadena =
  frequency [
    (9, cadenaConPunto),
    (1, arbitrary)
  ]
  where
    cadenaConPunto = do
      xs <- listOf (elements (['a'..'z'] ++ ['0'..'9']))
      ys <-  vectorOf 3 (elements (['a'..'z'] ++ ['0'..'9']))
      return (xs ++ "." ++ ys)

-- La propiedad es
prop_extension :: Property
prop_extension =
  forAll genCadena $ \cs ->
    all (== extension1 cs)
        [extension2 cs,
         extension3 cs,
         extension4 cs]

-- La comprobación es
--    λ> quickCheck prop_extension
--    +++ OK, passed 100 tests.

-- Comparación de eficiencia
-- =========================

-- La comparación es
--    λ> extension1 (replicate (10^7) 'a' ++ ".txt")
--    "txt"
--    (1.28 secs, 1,360,601,160 bytes)
--    λ> extension2 (replicate (10^7) 'a' ++ ".txt")
--    "txt"
--    (1.30 secs, 1,360,601,040 bytes)
--    λ> extension3 (replicate (10^7) 'a' ++ ".txt")
--    "txt"
--    (1.76 secs, 2,640,601,512 bytes)
--    λ> extension4 (replicate (10^7) 'a' ++ ".txt")
--    "txt"
--    (1.40 secs, 1,360,601,128 bytes)