Алгоритм фильтрации текстовых файлов
Представьте, что у вас есть файл .txt
следующей структуры:
>>> header
>>> header
>>> header
K L M
200 0.1 1
201 0.8 1
202 0.01 3
...
800 0.4 2
>>> end of file
50 0.1 1
75 0.78 5
...
Я хотел бы прочитать все данные, кроме строк, обозначенных символом >>>
и строками ниже строки >>> end of file
.
Пока я решил это, используя read.table(comment.char = ">", skip = x, nrow = y)
(x
и y
в настоящее время исправлены). Это считывает данные между заголовком и >>> end of file
.
Однако, я хотел бы сделать мою функцию немного более пластичной относительно количества строк. Данные могут иметь значения больше 800 и, следовательно, больше строк.
Я мог бы scan
или readLines
сохранить файл и посмотреть, какая строка соответствует >>> end of file
, и вычислить количество строк, которые нужно прочитать. Какой подход вы бы использовали?
Ответы
Ответ 1
Вот один из способов сделать это:
Lines <- readLines("foo.txt")
markers <- grepl(">", Lines)
want <- rle(markers)$lengths[1:2]
want <- seq.int(want[1] + 1, sum(want), by = 1)
read.table(textConnection(Lines[want]), sep = " ", header = TRUE)
Что дает:
> read.table(textConnection(Lines[want]), sep = " ", header = TRUE)
K L M
1 200 0.10 1
2 201 0.80 1
3 202 0.01 3
4 800 0.40 2
В предоставленном фрагменте данных (в файле foo.txt
и после удаления... строк).
Ответ 2
Вот несколько способов.
1) readLine
читает в строках файла в L
и устанавливает skip
число строк, которые нужно пропустить в начале, и end.of.file
к номеру строки строки, обозначающей конец данные. Затем команда read.table
использует эти две переменные для повторного чтения данных.
File <- "foo.txt"
L <- readLines(File)
skip <- grep("^.{0,2}[^>]", L)[1] - 1
end.of.file <- grep("^>>> end of file", L)
read.table(File, header = TRUE, skip = skip, nrow = end.of.file - skip - 2)
Вариантом будет использование textConnection
вместо File
в строке read.table
:
read.table(textConnection(L), header = TRUE,
skip = skip, nrow = end.of.file - skip - 2)
2) Другая возможность - использовать sed или awk/gawk. Рассмотрим эту однолинейную программу gawk. Программа выходит, если видит линию, обозначающую конец данных; в противном случае он пропускает текущую строку, если эта строка начинается с → > , и если ни одно из них не произойдет, она печатает строку. Мы можем передать foo.txt
через программу gawk и прочитать ее с помощью read.table
.
cat("/^>>> end of file/ { exit }; /^>>>/ { next }; 1\n", file = "foo.awk")
read.table(pipe('gawk -f foo.awk foo.txt'), header = TRUE)
Отличие состоит в том, что мы можем опустить часть /^>>>/ {next};
программы gawk, которая пропускает строки >>>
в начале и вместо этого использует comment = ">" in the
read.table`.