2012-03-29 3 views
0

Здравствуйте, я новичок в Haskell, и у меня проблемы с попыткой заставить этот скрипт работать. Этот скрипт читается в аргументах из командной строки и находит их в отдельном текстовом файле.Поиск и замена слов звездочкой, в текстовом файле

E.G: cat.txt | ./redact house big cat (in compiler)

Он редактирует определенные слова в текстовом файле, заменяя их звездочками (**) звездочками. Число звезд, используемых для каждого отредактированного слова, должно равняться количеству символов в слове.

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 '*') 

Однако, когда я пытаюсь скомпилировать это, GHCi возвращает ошибку:

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. 

Поэтому код:

putStr (redact txt arg1) 

вызывает проблему.

Заранее благодарю за любую помощь, и если вы можете улучшить код в любом случае, это было бы здорово.

EDIT:

Я хочу, чтобы ввести столько арг, насколько это возможно, оно не имеет значения, сколько арг вы входите, я попробовал:

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

, но я должен войти ТОЧНЫЕ 5 арг, Не важно, сколько я вхожу в args. Я думал использовать какую-то петлю, но я не уверен?

Снова благодарим вас за помощь.

ответ

1

Чтобы заставить его работать с несколькими аргументами, используйте getArgs, как и у вас есть. Проблема связана с

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

, где вы сравниваете строчные буквы одного слова с строчными буквами нескольких слов. Последнее не определено, вы хотели бы сравнить его с нижним регистром каждыйxWords. Поэтому сначала вам нужно привести их все в строчные буквы, это наиболее эффективно сделать, позвонив из основного redact txt (map lowercase arg1), а не только redact txt arg1. Затем вам нужно определить, является ли прочитанное слово в списком xWords, вот что такое функция elem.

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

Кстати, вы должны, возможно, не вызывать эту функцию foo, даже если это только локальное.

1

getArgs :: IO [String], поэтому после arg1 <- getArgs, arg1 имеет типа [String]: он содержит всех аргументов, передаваемых в программу, в виде списка. Но вы используете его как String, таким образом, ошибка: GHC ожидал arg1 быть String, но это [String].

Вы можете шаблон матча на результат, как это:

arg1:_ <- getArgs 

Это приводит к arg1 содержащий первый элемент списка, и отбрасывает остальную часть списка. Если вы не передадите аргумент, это приведет к ошибке выполнения. Конечно, если вы хотите более специализированное поведение (например, печатать ошибку, если аргументы не заданы), вы можете использовать более сложный метод извлечения первого аргумента, например выражение case.

Насколько улучшение вашей программы идет:

  • Вы можете упростить определение work с использованием композиции функции и map, а не список понимания: work = unwords . map foo . words (читайте: «Карта foo по всем элементам words, затем unwords их ").

  • redact можно упростить аналогичным образом, до redact input xWords = unlines . map work . lines $ input.

  • lowercase(w) лучше всего написано как lowercase w.

Но ваша программа выглядит в основном хорошо для меня, за исключением некоторых странностей (как отсутствующего :: в convertWord «s типа подписи, дополнительные 1 вы передадите ему в foo - но происходит в несколько беспорядочным отступа, Думаю, вы отредактировали код, прежде чем публиковать его). Я бы не сделал первые два изменения, если вы не понимаете, как они работают, и они удобны в написании кода.

+1

В соответствии с примером использование аргументов _all_ было тем, чего фактически хотел ОП. – leftaroundabout

+0

@leftaroundabout: Хм, справа. Меня обманули именованием 'arg1'. Ну, надеюсь, остальная часть моего совета будет полезна ... – ehird

Смежные вопросы