简体   繁体   中英

Haskell - Removing non-letter characters but ignoring white spaces?

I am very new to Haskell. I am trying to return a list of strings from a given string (which could contain non-letter characters) but I get a single string in the list.

The below code shows What I have tried so far:

toLowerStr xs = map toLower xs

--drop non-letters characters
dropNonLetters xs = words $ (filter (\x -> x `elem` ['a'..'z'])) $ toLowerStr xs
  • lowercase all the characters by using toLower function
  • remove non-letter characters by using filter function
  • return a list of strings by using words function

I think the filter function is removing the white spaces and therefore it becomes a single string. I tried using isSpace function but I don't know exactly how to implement it in this case.

What is it that I am doing wrong? I get this output:

λ> dropNonLetters "ORANGE, apple! APPLE!!"
["orangeappleapple"]

But I want to achieve the below output:

λ> dropNonLetters "ORANGE, apple! APPLE!!"
["orange","apple","apple"]

I think the filter function is removing the white spaces and therefore it becomes a single string.

That is correct. As filter predicate you write \\x -> x `elem` ['a'..'z'] . ['a'..'z'] is a list that contains lowercase letters, so for whitespace, the predicate will fail, and thus you should allow spaces as well.

We can for instance add the space character to the list:

dropNonLetters xs = words $ (filter (\x -> x `elem` ['a'..'z']))) $ toLowerStr xs

But this is inelegant and does not really explain itself. The Data.Char module however ships with two functions that are interesting here: isLower :: Char -> Bool , and isSpace :: Char -> Bool . We can use this like:

dropNonLetters xs = words $ (filter (\x -> )) $ toLowerStr xs

isLower and isSpace are not only more "descriptive" and elegant . Usually these functions will be faster than a membership check (which will usually be done in O(n) ), and furthermore it will also take into account tabs, new lines, etc.

We can also perform an eta-reduction on the function:

dropNonLetters = words  (filter (\x -> isLower x || isSpace x))  toLowerStr

This then produces:

Prelude Data.Char> dropNonLetters "ORANGE, apple! APPLE!!"
["orange","apple","apple"]

I advise you to rename the function dropNonLetters , since now it does not fully explain that it will generate a list of words. Based on the name, I would think that it only drops non-letters, not that it converts the string to lowercase nor that it constructs words.

here's an example of separating characters into separate string lists:

sortNumbers :: [Char] -> [String] sortNumbers args = filter (\\strings ->strings/= "") $ zipWith (\\x numbers -> filter (\\char -> char == numbers) x) (repeat args) ['1'..'9']

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM