如何获取文档每个部分的第一段和最后一段?

时间:2015-12-25 09:44:27

标签: string algorithm haskell

我在构建针对以下问题的算法时遇到了麻烦:给定一本教科书(this one),找到每个部分的每个第一段和最后一段。

通过传递newline参数,使用splitgroupifyfilter在Haskell中轻松获取每个段落,并且工作正常。然而,其余的对我来说很复杂(我只熟悉OOP)。如果我们将标题作为基本情况,则文本中将有两个标题字符串:一个在索引部分,一个在文本本身。程序如何区分它们?此外,代码如何知道两段之间是否有两个空行?

这是我尝试解决问题;

  1. 通过将文本拆分为段落

  2. 的元素,将每个段落放入一个数组中
  3. 搜索数组中标题的索引,找到每个标题的第二次出现以及该索引的名称

  4. 将paragraph_array [index + 1]作为第一个元素

  5. 将paragraph_array [index-1]作为上一节的最后一个元素。

  6. 我很困惑。任何帮助都将非常感激。

    更新:某个部分类似于每个标题的一部分。例如,微积分书可以包含12章,每章可以包含8个章节。我们需要考虑那本书只有一章,它有4-5个部分。 标题可以是INTEGRAL,LIMIT等。

1 个答案:

答案 0 :(得分:0)

以下是我将如何处理此问题的草图。

我假设你有一些功能isTitle :: String -> Bool可以 确定某个字符串是否是标题并且您是否有文本 分为段落和标题列表(即[String]类型)。

{-# LANGUAGE RecordWildCards #-}
module FindParagraphs where

import Data.Maybe

我从一个数据类型开始,将两个元素的光标放入一个列表中, 这种数据类型通常称为Zipper。

data TwoZip a =
  TwoZip { front :: [a]
         , first :: a
         , second :: a
         , back :: [a]
         }
  deriving (Eq, Show)

-- make a zipper from a list
mkZip :: [a] -> Maybe (TwoZip a)
mkZip (first:second:back) = Just (TwoZip [] first second back)
mkZip _ = Nothing

-- advance the zipper
advance :: TwoZip a -> Maybe (TwoZip a)
advance TwoZip{..}
  | (x:xs) <- back = Just (TwoZip (first:front) second x xs)
advance _ = Nothing

-- and rewind our zipper (not needed in this case but nice for
-- completeness sake)
rewind :: TwoZip a -> Maybe (TwoZip a)
rewind TwoZip{..}
  | (x:xs) <- front = Just (TwoZip xs x first (second:back))
rewind _ = Nothing

要找到所有第一段,我们会迭代段落并查看 在拉链的第一个元素,如果它是标题,我们知道 拉链中的下一个元素是第一段,然后我们前进!

findFirsts
  :: (String -> Bool) -- ^ is collection of words a title
  -> [String] -- ^ Titles and paragraphs
  -> [String] -- ^ last and first paragraphs
findFirsts isTitle paragraphs = reverse (go (fromJust (mkZip paragraphs)) [])
  where
    go
      :: TwoZip String
      -> [String]
      -> [String]
    go z@TwoZip{..} firsts =
      let
        firsts' =
          if isTitle first
          then second:firsts
          else firsts
      in case advance z of
        Nothing -> firsts'
        Just z' -> go z' firsts'

然后是一些(简化的)测试数据:

testData = map show [1,2,3,1,3,4,1,4,3]
isTitle = (== "1")

first_paragraphs = findFirsts isTitle testData

正如我们想要的那样:

λ> first_paragraphs
["2","3","4"]

你可能会弄清楚如何扩展它以找到 最后一段以及如何在一次迭代中完成它们。