【问题标题】:Extract chapters from text从文本中提取章节
【发布时间】:2019-09-18 00:39:13
【问题描述】:

与我的question 类似,我想在 R 中使用 Regex 提取字符串中的字符序列。我想从文本文档中提取部分,从而生成一个数据框,其中每个子部分都被视为自己的矢量,用于进一步的文本挖掘。这是我的示例数据:

chapter_one <- c("One morning, when Gregor Samsa woke from troubled dreams, he found himself transformed in his bed into a horrible vermin.
1 Introduction
He lay on his armour-like back, and if he lifted his head a little he could see his brown belly, slightly domed and divided by arches into stiff sections. 
1.1 Futher
The bedding was hardly able to cover it and seemed ready to slide off any moment. 
1.1.1 This Should be Part of One Point One
His many legs, pitifully thin compared with the size of the rest of him, waved about helplessly as he looked.
1.2 Futher Fuhter
'What's happened to me?' he thought. It wasn't a dream. His room, a proper human room although a little too small, lay peacefully between its four familiar walls.")

这是我的预期输出:

chapter_id <- (c("1 Introduction", "1.1 Futher", "1.2 Futher Futher")) 
text <- (c("He lay on his armour-like back, and if he lifted his head a little he could see his brown belly, slightly domed and divided by arches into stiff sections.", "The bedding was hardly able to cover it and seemed ready to slide off any moment. His many legs, pitifully thin compared with the size of the rest of him, waved about helplessly as he looked.", "'What's happened to me?' he thought. It wasn't a dream. His room, a proper human room although a little too small, lay peacefully between its four familiar walls."))

chapter_one_df <- data.frame(chapter_id, text)

到目前为止我尝试的是这样的:

library(stringr)

regex_chapter_heading <- regex("
          [:digit:]     # Digit number 
                        # MISSING: Optional dot and optional second digit number 
          \\s           # Space
          ([[:alpha:]]) # Alphabetic characters (MISSING: can also contain punctuation, as in 'Introduction - A short introduction')
                     ", comments = TRUE)

read.table(text=gsub(regex_chapter_heading,"\\1:",chapter_one),sep=":")

到目前为止,这并没有产生预期的输出 - 因为如前所述,仍然缺少部分正则表达式。非常感谢任何帮助!

【问题讨论】:

  • 任何以数字开头的行都是“章节”?也许:split(txt, grepl("^[1:9]", txt))
  • 这是个好主意,但我只想包含直到第二级(1.1 等)的章节。在我的原始文本集中,我有像“2.31.1.1”这样的子章节,我想成为“更大”子章节(在本例中为“2.31”)的一部分。

标签: r regex dataframe


【解决方案1】:

您可以尝试以下方法:1)替换以三个点分隔的数字开头的所有行(因为这些是前面项目符号点的延续),以及 2)使用数字 + 可选的点 + 数字作为分隔符提取部分模式,同时将第一行和后面的行捕获到单独的捕获组中:

library(stringr)
# Replace lines starting with N.N.N+ with space
chapter_one <- gsub("\\R\\d+(?:\\.\\d+){2,}\\s+[A-Z].*\\R?", " ", chapter_one, perl=TRUE)
# Split into IDs and Texts
data <- str_match_all(chapter_one, "(?sm)^(\\d+(?:\\.\\d+)?\\s+[A-Z][^\r\n]*)\\R(.*?)(?=\\R\\d+(?:\\.\\d+)?\\s+[A-Z]|\\z)")
# Get the chapter ID column
chapter_id <- trimws(data[[1]][,2])
# Get the text ID column
text <- trimws(data[[1]][,3])
# Create the target DF
chapter_one_df <- data.frame(chapter_id, text)

输出:

         chapter_id
1    1 Introduction
2        1.1 Futher
3 1.2 Futher Fuhter
                                                                                                                                                                                              text
1                                       He lay on his armour-like back, and if he lifted his head a little he could see his brown belly, slightly domed and divided by arches into stiff sections.
2 The bedding was hardly able to cover it and seemed ready to slide off any moment.  His many legs, pitifully thin compared with the size of the rest of him, waved about helplessly as he looked.
3                               'What's happened to me?' he thought. It wasn't a dream. His room, a proper human room although a little too small, lay peacefully between its four familiar walls.

\R\d+(?:\.\d+){2,}\s+[A-Z].*\R? 模式用于将要“排除”的行替换为空格:

  • \R - 换行
  • \d+ - 1 位以上
  • (?:\.\d+){2,} - . 和 1+ 位重复两次或多次
  • \s+ - 1+ 个空格(替换为 \h 以匹配单个水平空格,或 \h+ 以匹配它们 1 个或多个)
  • [A-Z] - 大写字母
  • .* - 除换行符之外的任何 0+ 个字符,尽可能多,直到行尾
  • \R? - 一个可选的换行字符序列。

第二个正则表达式相当复杂:

(?sm)^(\d+(?:\.\d+)?\s+[A-Z][^\r\n]*)\R(.*?)(?=\R\d+(?:\.\d+)?\s+[A-Z]|\z)

请参阅regex demo

详情

  • (?sm) - s 使 . 匹配任何字符,m 使 ^ 匹配行首
  • ^ - 行首
  • (\d+(?:\.\d+)?\s+[A-Z][^\r\n]*) - 第 1 组:一个或多个数字,然后是 1 或 0 个重复 . 和 1+ 数字、1+ 空格、一个大写字母、除 CR 和 LF 符号之外的任何 0+ 字符,尽可能多,
  • \R - 换行
  • (.*?) - 第 2 组:任何 0+ 个字符,尽可能少,直到第一次出现
    • \R\d+(?:\.\d+)?\s+[A-Z] - 换行符,一个或多个数字,然后是 1 或 0 次 . 和 1+ 数字,1+ 空格,一个大写字母
    • | - 或
    • \z - 字符串结束。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-06-05
    • 1970-01-01
    • 1970-01-01
    • 2012-01-09
    • 1970-01-01
    • 2023-03-25
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多