【问题标题】:An algorithm for filtering text files一种过滤文本文件的算法
【发布时间】:2011-06-05 11:21:34
【问题描述】:

假设您有一个具有以下结构的.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) 解决了这个问题(xy 目前已修复)。这会读取标题和>>> end of file 之间的数据。

但是,我想让我的函数在行数方面更具可塑性。数据的值可能大于 800,因此行数更多。

我可以scanreadLines 文件并查看哪一行对应于>>> end of file 并计算要读取的行数。你会使用什么方法?

【问题讨论】:

  • 请提供一些虚拟数据。 =)
  • @aL3xa:sn-p 是否已经显示不足?

标签: r import


【解决方案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

在您提供的数据 sn-p 上(在文件 foo.txt 中,并在删除 ... 行之后)。

【讨论】:

  • +1,很高兴了解rle,我以前没有使用过。我想知道是否有办法通过添加可选的EOF 参数来修改read.table(和/或scan 和/或readLines)的定义,以便在遇到@987654329 时退出@ 细绳。这样我们就可以一次性完成,而不是 2 次。
  • EOF 参数将是一个不错的补充。
  • 我希望有一种方法可以将可选的 EOF arg 添加到 scan 的源定义中,但它调用 .Internal(scan...),所以唯一的方法是更改​​内部 (C? ) 扫描代码...
  • 函数 (lapply) 中 textConnection() 的一个微小副作用是连接会被 gc()-ed,这会产生一个恼人的警告(无害)。这可以在 textConnection() 调用后使用 closeAllConnections() 解决。
  • @Roman;好点子。如果我经常使用上述内容,我会将其包装在一个函数中,保存con &lt;- textConnection(Lines[want]) 的输出并在函数主体中包含一个on.exit(close(con)),以确保在函数退出时仅关闭生成的连接,通常或异常。
【解决方案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)

一种变体是在read.table 行中使用textConnection 代替File

read.table(textConnection(L), header = TRUE, 
   skip = skip, nrow = end.of.file - skip - 2)

2) 另一种可能性是使用 sed 或 awk/gawk。考虑一下这一行 gawk 程序。如果程序看到标记数据结束的行,则程序退出;否则,如果该行以 >>> 开头,则它会跳过当前行,如果两者都没有发生,则打印该行。我们可以通过 gawk 程序管道 foo.txt 并使用 read.table 读取它。

cat("/^>>> end of file/ { exit }; /^>>>/ { next }; 1\n", file = "foo.awk")
read.table(pipe('gawk -f foo.awk foo.txt'), header = TRUE)

对此的一种变体是,我们可以省略 gawk 程序的 /^&gt;&gt;&gt;/ {next}; 部分,它会跳过开头的 &gt;&gt;&gt; 行,而是使用 comment = "&gt;" in theread.table` 调用。

【讨论】:

  • 如果您无法提前预见文件的结构,那么 awk/gawk 解决方案会非常方便。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-12-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多