2012-03-29 9 views
0

Hallo ich bin neu bei Haskell und ich habe Probleme, dieses Skript zu arbeiten. Dieses Skript liest Argumente von einer Befehlszeile ein und findet sie in einer separaten Textdatei.Suchen und Ersetzen von Wörtern mit Stern, in einer Textdateiausgabe

E.G: cat.txt | ./redact Haus große Katze (im Compiler)

Es redigiert bestimmte Wörter in einer Textdatei, indem sie sie durch Sterne (**) Sterne ersetzt. Die Anzahl der Sterne für jedes redigierte Wort sollte der Anzahl der Zeichen im Wort entsprechen.

module Main where 

import System 
import Data.Char 
import Data.List 

lowercase :: String -> String 
lowercase = map toLower 

main = do 
arg1 <- getArgs 
txt <- getContents 
putStr (redact txt arg1) 

redact :: String -> String -> String 
redact input xWords = unlines [ work line | line <- lines input ] 
where work line = unwords [ foo word | word <- words line ] 
    foo w | lowercase(w) == lowercase(xWords) = convertWord w 1 
    | otherwise       = w 

convertWord Eq a => [a] -> [a] 
convertWord = map (const '*') 

aber wenn ich versuche, dies zu kompilieren, gibt GHCi den Fehler:

redact.hs:13:38: 
    Couldn't match expected thye 'Char' with actual type '[Char]' 
    Expected type: String 
    Actual type: [String] 
    In the second argument of 'redact', namely 'arg1' 
    In the first of 'putStr', namely '<redact txt arg1>' 
Failed, module loaded: none. 

So ist der Code:

putStr (redact txt arg1) 

das Problem verursacht.

Vielen Dank im Voraus für jede Hilfe und wenn Sie den Code in jedem Fall verbessern können, wäre das großartig.

EDIT:

ich so viele Argumente wie möglich eingeben möchten, spielt es keine Rolle, wie viele args Sie eingeben, habe ich versucht:

(arg1:arg2:arg3:arg4:arg5:_) <- getArgs 

aber ich muss EXACT 5 args eingeben, Es sollte egal sein, wie viele Argumente ich eintrage. Ich dachte an eine Art Loop, aber ich bin mir nicht sicher?

Nochmals vielen Dank für Ihre Hilfe.

Antwort

1

Um es mit mehreren Argumenten zu arbeiten, verwenden Sie getArgs, wie Sie es haben. Das Problem liegt darin,

foo w | lowercase(w) == lowercase(xWords) = convertWord w 1 
     | otherwise       = w 

wo Sie die Kleinbuchstaben eines Wortes mit Kleinbuchstaben mehrerer Wörter vergleichen. Letzteres ist nicht definiert, Sie möchten es mit dem Kleinbuchstaben vonxWords vergleichen. Also zuerst müssen Sie sie alle in Kleinbuchstaben bringen, das ist am effizientesten durch den Aufruf von Haupt redact txt (map lowercase arg1) statt nur redact txt arg1. Dann müssen Sie feststellen, ob ein gelesenes Wort ist in die Liste xWords, das ist, was die elem Funktion ist für da.

foo w | lowercase w `elem` xWords = convertWord w 1 
     | otherwise     = w 

BTW, sollten Sie vielleicht nicht diese Funktion aufrufen foo auch wenn es nur eine lokale.

1

getArgs :: IO [String], so dass nach arg1 <- getArgs, arg1 hat den Typ [String]: es enthält alle die an Ihr Programm übergebenen Argumente als Liste. Aber Sie verwenden es als String, damit der Fehler: GHC erwartet arg1 zu einem String, aber es ist ein [String].

Sie können Muster-Spiel auf das Ergebnis wie folgt aus:

arg1:_ <- getArgs 

Dies führt zu arg1 das erste Element der Liste enthält, und verwirft den Rest der Liste. Wenn Sie kein Argument übergeben, führt dies zu einem Laufzeitfehler. Wenn Sie ein spezielleres Verhalten wünschen (z. B. einen Fehler ausgeben, wenn keine Argumente angegeben sind), könnten Sie natürlich eine komplexere Methode zum Extrahieren des ersten Arguments verwenden, z. B. einen case Ausdruck.

Soweit Verbesserungen an Ihrem Programm gehen:

  • Sie können die Definition von work mit der Funktion Zusammensetzung und map anstatt die Liste Verständnis vereinfachen: work = unwords . map foo . words (sprich: „map foo über alle Elemente die words, dann unwords sie ").

  • redact kann ähnlich vereinfacht werden, zu redact input xWords = unlines . map work . lines $ input.

  • lowercase(w) ist besser geschrieben als lowercase w.

Aber Ihr Programm sieht für mich im Grunde in Ordnung, abgesehen von einigen Merkwürdigkeiten (wie die fehlende :: in convertWord ‚s Art Unterschrift, übergeben die zusätzliche 1 Sie es in foo - aber durch die etwas erratisch Einbuchtung geht, Ich denke du hast den Code vor dem Posten bearbeitet. Ich würde die ersten beiden Änderungen nicht vornehmen, wenn Sie nicht verstehen, wie sie funktionieren, und dass Sie so komfortabel Code schreiben.

+1

Laut dem Beispiel war die Verwendung von _all_ Argumenten das, was das OP eigentlich wollte. – leftaroundabout

+0

@leftaroundabout: Hmm, richtig. Ich wurde durch die Benennung von "arg1" getäuscht. Naja, hoffentlich ist der Rest meines Rates hilfreich ... – ehird