epubr 0.6.0 CRAN release

Reorder sections based on pattern in text

Some poorly formatted e-books have their internal sections occur in an arbitrary order. This can be frustrating to work with when doing text analysis on each section and where order matters. Just like recombining into new sections based on a pattern, sections that are out of order can be reordered based on a pattern. This requires a bit more work. In this case the user must provide a function that will map something in the matched pattern to an integer representing the desired row index.

Continue with the Dracula example, but with one difference. Even though the sections were originally broken at arbitrary points, they were in chronological order. To demonstrate the utility of epub_reorder, first randomize the rows so that chronological order can be recovered.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
set.seed(1)
x2$data[[1]] <- sample_frac(x2$data[[1]]) # randomize rows for example
x2$data[[1]]
#> # A tibble: 27 x 4
#> section text nword nchar
#> 
#> 1 ch08 "CHAPTER VIIIMINA MURRAY'S JOURNAL\nSame day, 11 o'~ 6267 32596
#> 2 ch10 "CHAPTER X\nLetter, Dr. Seward to Hon. Arthur Holmw~ 5932 30730
#> 3 ch15 "CHAPTER XVDR. SEWARD'S DIARY-continued.\nFOR a whi~ 5803 29705
#> 4 ch22 "CHAPTER XXIIJONATHAN HARKER'S JOURNAL\n3 October.-~ 5450 28081
#> 5 ch05 "CHAPTER V\nLetter from Miss Mina Murray to Miss Lu~ 3546 18005
#> 6 ch20 "CHAPTER XXJONATHAN HARKER'S JOURNAL\n1 October, ev~ 5890 31151
#> 7 ch24 "CHAPTER XXIVDR. SEWARD'S PHONOGRAPH DIARY, SPOKEN ~ 6272 32065
#> 8 ch14 "CHAPTER XIVMINA HARKER'S JOURNAL\n23 September.-Jo~ 6411 32530
#> 9 ch12 "CHAPTER XIIDR. SEWARD'S DIARY\n18 September.-I dro~ 7285 37868
#> 10 ch02 "CHAPTER IIJONATHAN HARKER'S JOURNAL-continued\n5 M~ 5476 28462
#> # ... with 17 more rows

It is clear above that sections are now out of order. It is common enough to load poorly formatted EPUB files and yield this type of result. If all you care about is the text in its entirely, this does not matter, but if your analysis involves trends over the course of a book, this is problematic.

For this book, you need a function that will convert an annoying Roman numeral to an integer. You already have the pattern for finding the relevant information in each text section. You only need to tweak it for proper substitution. Here is an example:

1
f <- function(x, pattern) as.numeric(as.roman(gsub(pattern, "\1", x)))

This function is passed to epub_reorder. It takes and returns scalars. It must take two arguments: the first is a text string. The second is the regular expression. It must return a single number representing the index of that row. For example, if the pattern matches CHAPTER IV, the function should return a 4.

epub_reorder takes care of the rest. It applies your function to every row in the the nested data frame and then reorders the rows based on the full set of indices. Note that it also repeats this for every row (book) in the primary data frame, i.e., for every nested table. This means that the same function will be applied to every book. Therefore, you should only use this in bulk on a collection of e-books if you know the pattern does not change and the function will work correctly in each case.

The pattern has changed slightly. Parentheses are used to retain the important part of the matched pattern, the Roman numeral. The function f here substitutes the entire string (because now it begins with ^ and ends with .*) with only the part stored in parentheses (In f, this is the \\1 substitution). epub_reorder applies this to all rows in the nested data frame:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
x2 <- epub_reorder(x2, f, "^CHAPTER ([IVX]+).*")
x2$data[[1]]
#> # A tibble: 27 x 4
#> section text nword nchar
#> 
#> 1 ch01 "CHAPTER IJONATHAN HARKER'S JOURNAL\n(Kept in short~ 5694 30602
#> 2 ch02 "CHAPTER IIJONATHAN HARKER'S JOURNAL-continued\n5 M~ 5476 28462
#> 3 ch03 "CHAPTER IIIJONATHAN HARKER'S JOURNAL-continued\nWH~ 5703 29778
#> 4 ch04 "CHAPTER IVJONATHAN HARKER'S JOURNAL-continued\nI A~ 5828 30195
#> 5 ch05 "CHAPTER V\nLetter from Miss Mina Murray to Miss Lu~ 3546 18005
#> 6 ch06 "CHAPTER VIMINA MURRAY'S JOURNAL\n24 July. Whitby.-~ 5654 29145
#> 7 ch07 "CHAPTER VIICUTTING FROM \"THE DAILYGRAPH,\" 8 AUGU~ 5567 29912
#> 8 ch08 "CHAPTER VIIIMINA MURRAY'S JOURNAL\nSame day, 11 o'~ 6267 32596
#> 9 ch09 "CHAPTER IX\nLetter, Mina Harker to Lucy Westenra.\~ 5910 30129
#> 10 ch10 "CHAPTER X\nLetter, Dr. Seward to Hon. Arthur Holmw~ 5932 30730
#> # ... with 17 more rows

It is important that this is done on a nested data frame that has already been cleaned to the point of not containing extraneous rows that cannot be matched by the desired pattern. If they cannot be matched, then it is unknown where those rows should be placed relative to the others.

If sections are both out of order and use arbitrary break points, it would be necessary to reorder them before you split and recombine. If you split and recombine first, this would yield new sections that contain text from different parts of the e-book. However, the two are not likely to occur together; in fact it may be impossible for an EPUB file to be structured this way. In developing epubr, no such examples have been encountered. In any event, reordering out of order sections essentially requires a human-identifiable pattern near the beginning of each section text string, so it does not make sense to perform this operation unless the sections have meaningful break points.