Подтвердить что ты не робот

Алгоритм фильтрации текстовых файлов

Представьте, что у вас есть файл .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, и вычислить количество строк, которые нужно прочитать. Какой подход вы бы использовали?

4b9b3361

Ответ 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`.