Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/haskell/8.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/elixir/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Haskell-在不丢失空格的情况下,将字符串中每个单词的第一个字母大写_Haskell - Fatal编程技术网

Haskell-在不丢失空格的情况下,将字符串中每个单词的第一个字母大写

Haskell-在不丢失空格的情况下,将字符串中每个单词的第一个字母大写,haskell,Haskell,我正在做一个练习,要求我编写一个函数,将字符串中所有单词的首字母大写 以下是我迄今为止所做的: upperFirst:: String -> String upperFirst str = let upperFirstForEachWord (firstLetter:others) = toUpper firstLetter : map toLower others in unwords (map upp

我正在做一个练习,要求我编写一个函数,将字符串中所有单词的首字母大写

以下是我迄今为止所做的:

upperFirst:: String -> String
upperFirst str =  let 
                      upperFirstForEachWord (firstLetter:others) = toUpper firstLetter : map toLower others
                  in unwords  (map upperFirstForEachWord (words str))
这就是它的工作原理:

upperFirst "" =   ""
upperFirst "hello friends!" = "Hello Friends!"
而且:

upperFirst " " =  ""
upperFirst " a a a " = "A A A"
由于函数
words
,我失去了开头、结尾和两个空格

如何递归地保存它们(而不处理所有可能的情况)


谢谢你的帮助

模式匹配是你的朋友

import Data.Char

upperFirst :: String -> String
upperFirst (c1:c2:rest) =
    if isSpace c1 && isLower c2
        then c1 : toUpper c2 : upperFirst rest
        else c1 : upperFirst (c2:rest)
upperFirst s = s
此函数唯一的问题是第一个字符不会大写(也会影响单个字符串),但如果确实需要该功能,则只需将对该函数的调用包装到另一个处理这些特殊情况的函数中:

upperFirst' = <the implementation above>

upperFirst [] = []
upperFirst [c] = [toUpper c]  -- No-op on non-letters
upperFirst (s:str) = upperFirst' (toUpper s:str)
例如

减少到

zipWith upper
    " a test for    upperFirst  "
    "a test for    upperFirst  "
如果第一个字符串中的符号是空格,第二个字符串中相同位置的符号是小写字母,则将其设为大写,否则返回相同的值。所以

  • 上部''a'='a'
  • 上部的“a”=''
  • 上部''t'='t'
  • 上部的't'e'='e'

等等。因此,结果是
“对UpperFirst的测试”

而不是像
单词那样提取单词,只需拆分字符串,使每个单词的开头也位于列表的开头。正如郝莲所评论的,这可以通过
splitOn
来实现,但标准也可以做到这一点:

import Data.List
import Data.Char

upperFirst = concat
           . map (\(c:cs) -> toUpper c : cs)
           . groupBy (\a b -> isSpace a == isSpace b)
工作原理:它将所有空格或所有非空格的字符分组在一起。然后,它将每个子字符串的开头大写(对空白也这样做有点低效,但无害),然后将所有字符串重新连接在一起

正如user3237465所言,
map
concat
的组合非常常见,并且是某事物的特例。此外,当通过某个谓词进行分组或排序时,还有一种方法非常方便。因此,你也可以这样写

import Control.Monad
import Data.Function

upperFirst = groupBy ((==)`on`isSpace) >=> \(c:cs) -> toUpper c : cs
要加满它,您可以使用修改内容,对于上壳部分:

import Control.Lens

upperFirst = groupBy ((==)`on`isSpace) >=> ix 0 %~ toUpper

此问题是典型的扫描:

>>> scanl (\old new -> if isSpace old then toUpper new else new) ' ' " hello  world  "
"  Hello  World  " 
“种子”的初始状态(这里是一个空格)添加在开头,但尾部在这里是合法的。请参阅
scanl
的实现,并将其与具有不同优点的其他扫描功能进行比较。以下是一个简单的版本:

scan op state []     = state : []
scan op state (x:xs) = state : scan op (op state x) xs
可以通过内联编写函数

op old new = if isSpace old then toUpper new else new
进入定义

myscan state []     = state : []
myscan state (x:xs) = state : myscan (if isSpace state then toUpper x else x) xs
以空格开始,然后取尾部:

titlecase = tail . myscan ' '
那么在ghci我明白了

>>> titlecase "  hello    world  "
"  Hello    World  "
或者您可以直接使用我们定义的常规
scan

>>> let op old new = if isSpace old then toUpper new else new

>>> scan op ' ' " hello   world  "
"  Hello   World  "

>>> tail $ scan op ' ' " hello   world  "
" Hello   World  "
这与非常相似,但我认为
mapAccumL
scanl
更适合:

upperFirst :: Traversable t => t Char -> t Char
upperFirst = snd . mapAccumL go True where
  go lastSpace x
     | isSpace x = (True, x)
     | lastSpace = (,) False $! toUpper x
     | otherwise = (False, x)

我认为任何使用
单词
的解决方案都会遇到这样的问题:
单词
单词
不是完美的反义词,除了双/三等空格外,它们总是会删除前导/尾随空格。尝试编写一个没有
单词的解决方案
unwords
。或者,请参阅,哪个更小心。尝试编写一个递归解决方案,它类似于
map
函数,但也传递一段状态
shouldnewitnonWhiteSpaceCharBeCapitalized::Bool
,然后查看是否可以在数据中找到一个更高阶的函数。捕获这种递归类型的列表。很好。为什么不
concatMap
?@user3237465:我怀疑它是否能增加清晰度,但我喜欢它。这将用空格取代制表符和换行符。哎呀!很抱歉我弄糊涂了。另一种包装方式是
drop 1。第一名'。(“”:)
>>> titlecase "  hello    world  "
"  Hello    World  "
>>> let op old new = if isSpace old then toUpper new else new

>>> scan op ' ' " hello   world  "
"  Hello   World  "

>>> tail $ scan op ' ' " hello   world  "
" Hello   World  "
upperFirst :: Traversable t => t Char -> t Char
upperFirst = snd . mapAccumL go True where
  go lastSpace x
     | isSpace x = (True, x)
     | lastSpace = (,) False $! toUpper x
     | otherwise = (False, x)