在文本文件输出中查找并替换带星号的单词

时间:2012-03-29 22:20:34

标签: haskell

你好我是Haskell的新手,我在尝试让这个脚本工作时遇到了问题。此脚本从命令行读入参数,并在单独的文本文件中查找。

E.G:cat.txt | ./redact house big cat(编译器中)

它通过用星号(**)星号替换它们来编辑文本文件中的某些单词。每个编辑单词使用的星号数应该等于单词中的字符数。

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)

造成了这个问题。

提前感谢您提供任何帮助,如果您可以改进代码,那就太棒了。

编辑:

我想输入尽可能多的args,无论你输入多少args,我都试过:

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

但我必须输入EXACT 5 args,我输入的args数量无关紧要。 我在考虑使用某种循环,但我不确定?

再次感谢您的帮助。

2 个答案:

答案 0 :(得分:1)

getArgs :: IO [String],因此在arg1 <- getArgs之后,arg1的类型为[String]:它包含所有传递给您的程序的参数,作为名单。但是您将其用作String,因此错误:GHC预期arg1String,但它是[String]

您可以对结果进行模式匹配,如下所示:

arg1:_ <- getArgs

这导致arg1包含列表的第一个元素,并丢弃列表的其余部分。如果不传递参数,则会导致运行时错误。当然,如果您想要更专业的行为(比如,在没有给出参数的情况下打印错误),您可以使用更复杂的方法来提取第一个参数,例如case表达式。

对于您的计划的改进:

  • 您可以使用函数组合和work而不是列表推导来简化map的定义:work = unwords . map foo . words(读取:“map foo覆盖所有words的元素,然后是unwords他们“。

  • redact可以简化为redact input xWords = unlines . map work . lines $ input

  • lowercase(w)最好写成lowercase w

但是你的程序对我来说看起来基本上没问题,除了一些奇怪之处(比如::类型签名中缺少convertWord,你在{{{{}}传递给它的额外1 1}} - 但是通过稍微不稳定的缩进,我猜你在发布之前编辑了代码)。我不会做出前两个更改,除非你了解它们是如何工作的,并且很乐意编写这样的代码。

答案 1 :(得分:1)

要使其与多个参数一起使用,请使用getArgs。问题在于

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

将一个单词的小写字母与多个单词的小写字母进行比较。后者未定义,您希望将其与xWords的每个的小写字母进行比较。首先,您需要将它们全部设置为小写,通过从主redact txt (map lowercase arg1)调用而不仅仅是redact txt arg1来最有效地完成。然后,您需要确定读取的单词是 in 列表xWords,这就是elem函数的用途。

foo w | lowercase w `elem` xWords = convertWord w 1
      | otherwise                 = w
顺便说一下,即使它只是本地函数,也不应该调用此函数foo