Пока на скриншоте строки выглядят так, как будто они находятся на постоянном уровне каждый,
они на самом деле не являются. Части «XXX ...:» и «TOTAL:» находятся в координатах y 469.45, 457.95 и 446.45, в то время как части «# ..», «1» и «2» находятся в координатах y 468.65, 457.15 и 445.65.
Чтобы рассматривать горизонтальный текст в одной строке, извлечение текста iText с использованием стратегии удаления текста по умолчанию (LocationTextExtractionStrategy
) требует, чтобы y-координаты были одинаковыми после кастинга на int
. (На самом деле это несколько упрощено, для всего изображения смотрите LocationTextExtractionStrategy.TextChunkLocationDefaultImp
)
В данном случае это имеет место только для средней строки (int) 457.95 = 457 = (int) 457.15
. Таким образом, извлечение текста по умолчанию приводит к:
XXXXXX XXXXX XXXXX : TOTAL :
#*2 1
XXXXXX XXXXX XXXXX : #*3 TOTAL : 2
XXXXXX XXXXX XXXXX: TOTAL :
#15 1
. В таких ситуациях вам нужна стратегия извлечения текста, которая распознает строки по-разному. Если вы, например, используйте HorizontalTextExtractionStrategy
или HorizontalTextExtractionStrategy2
(в зависимости от вашей версии iText, первая для iText 5.5.8, последняя для нового iText 5.5.x версии) из этого ответа вы получите:
XXXXXX XXXXX XXXXX : #*2 TOTAL : 1
XXXXXX XXXXX XXXXX : #*3 TOTAL : 2
XXXXXX XXXXX XXXXX: #15 TOTAL : 1
(проверено с использованием метода TextExtraction.java testTest_pdf()
)
Кстати, это не означает, что по умолчанию следует переключиться на HorizontalTextExtractionStrategy2
. Этот метод также имеет свои недостатки, в частности, он рассматривает всю ширину страницы (или, по крайней мере, всю страницу, если извлекать по фильтру), чтобы найти строки. Таким образом, если ваша страница, например. имеет два столбца текста nect друг к другу, а строки имеют одинаковую приблизительную высоту только за столбец, эта стратегия, скорее всего, вернет полный мусор.
OP задал в комментарии
Можете ли вы дать мне краткое объяснение того, что делает
blockquote>HorizontalTextExtractionStrategy
?При сканировании страницы эта стратегия просто собирает текстовые фрагменты из инструкции по рисованию текста с их координатами ограничительной рамки.
Когда его попросят получить результирующий текст, он в первом прогоне проецирует все эти ограничивающие прямоугольники на ось y системы координат страницы.
Во втором проходе он интерпретирует каждый подключенный компонент изображения этой проекции как диапазон координаты y одной строки: он выполняет итерацию по этим подключенным компонентам сверху вниз; для каждого компонента он принимает все куски, проецируемые в него, сортирует их по их координате x, добавляет места, где это необходимо, и объединяет их в текстовую строку.
Наконец, он возвращает конкатенацию этих строк (с линейными каналами
LocationTextExtractionStrategy
говорит: « Этот рендерер отслеживает ориентацию и расстояние (как перпендикулярно, так и параллельно) единичному вектору ориентации. Текст упорядочивается по ориентация, затем перпендикуляр, затем параллельное расстояние. Текст с тем же перпендикулярным расстоянием, но с другим параллельным расстоянием рассматривается как находящийся на одной линии. «Это не имеет большого смысла для меня.По сути, это также стратегия с двумя проходами, в первом проходе, собирающая все текстовые фрагменты с координатами, а во втором - размещение строк. Однако эта стратегия учитывает ориентацию базовой линии кусков и сначала сортирует по углу базовой линии.
Среди кусков с одинаковым базовым углом он считает, что куски принадлежат к одной и той же текстовой строке если их (ограниченные) базовые линии находятся на одной и той же (неограниченной) линии.
Куски, считающиеся принадлежащими к одной и той же текстовой строке, затем сортируются в направлении ориентации записи, и места, где это необходимо, вставлены.
Сравнение, проведенное в соответствии с этой стратегией, основано на значениях
int
и поэтому допускает крошечный бит дисперсии
Ах, я думаю, что поняла это сейчас.
Это связано со структурой формальных аргументов функции:
Если аргумент определен без значения по умолчанию, R будет жаловаться, когда вы вызываете функцию, не указывая, что это может произойти технически быть в состоянии найти его в своей области.
Один из способов запустить лексическую область видимости, даже если вы не хотите определять значение по умолчанию, - это установить значения по умолчанию «на лету» во время выполнения с помощью rlang::fn_fmls()
.
foo <- function(fun) {
env_enclosing <- rlang::fn_env(fun)
env_enclosing$x <- 5
fun()
}
# No argument at all -> lexical scoping takes over
baz <- function() x
foo(baz)
#> [1] 5
# Set defaults to desired values on the fly at run time of `foo()`
foo <- function(fun) {
env_enclosing <- rlang::fn_env(fun)
env_enclosing$x <- 5
fmls <- rlang::fn_fmls(fun)
fmls$x <- substitute(get("x", envir = env_enclosing, inherits = FALSE))
rlang::fn_fmls(fun) <- fmls
fun()
}
bar <- function(x) x
foo(bar)
#> [1] 5
Я действительно не могу последовать вашему примеру, так как я незнаком с библиотекой rlang
, но я думаю, что хорошим примером замыкания в R будет:
bucket <- function() {
n <- 1
foo <- function(x) {
assign("n", n+1, envir = parent.env(environment()))
n
}
foo
}
bar <- bucket()
, потому что bar()
является определением в функциональной среде bucket
его родительской средой является bucket
, и поэтому вы можете перенести туда некоторые данные. Каждый раз, когда вы запускаете его, вы изменяете среду bucket
:
bar()
[1] 2
bar()
[1] 3
bar()
[1] 4