关于haskell:在文本文件输出中查找并用星号替换单词

Finding and replacing words with asterisk, in a text file output

您好,我是Haskell的新手,我在尝试使此脚本正常工作时遇到问题。该脚本从命令行读取争论,然后在单独的文本文件中找到争论。

例如:cat.txt | ./redact house大猫(在编译器中)

它将文本文件中的某些单词替换为星号(**),以对其进行编辑。每个编辑的单词所用的星标数量应等于该单词中的字符数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
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返回错误:

1
2
3
4
5
6
7
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.

所以代码:

1
putStr (redact txt arg1)

造成了问题。

预先感谢您提供的任何帮助,如果您可以以任何方式改进代码,那将是很好的。

编辑:

我想输入尽可能多的参数,无论您输入多少参数,我都尝试过:

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

但我必须输入精确的5个参数,我输入多少个参数都没关系。
我当时在考虑使用某种循环,但不确定吗?

再次感谢您的帮助。


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

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

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

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

顺便说一句,即使它只是一个本地函数,也可能不应调用此函数foo


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

您可以像这样对结果进行模式匹配:

1
arg1:_ <- getArgs

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

至于对程序的改进:

  • 您可以使用函数组合和map而不是列表理解来简化work的定义:work = unwords . map foo . words(阅读:"在words的所有元素上映射foo,然后在unwords上进行映射") 。

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

  • lowercase(w)最好写为lowercase w

但是您的程序对我来说基本上看起来不错,除了一些奇怪的地方(例如convertWord的类型签名中缺少的::,还有在foo中传递给它的其他1),但缩进有些不稳定,我猜您在发布代码之前已对其进行了编辑)。除非您了解它们的工作原理,并且愿意编写这样的代码,否则我不会进行前两个更改。