【问题标题】:Read text file where the columns have specific format读取列具有特定格式的文本文件
【发布时间】:2019-10-20 08:09:50
【问题描述】:

我正在使用 Fortran,我需要读取一个包含 3 列的文件。问题是第三列是整数的组合,例如120120101,我需要将每个值分隔在不同的列中。

通常,我手动删除前 2 列,因此文件如下所示:

Info
0120012545
1254875541
0122110000
2254879933

要读取每个值都在不同列中的文件,我可以使用以下 Fortran 子例程:

subroutine readF(imp, m, n)
  implicit none
  integer :: n,m,i,imp(n,m)
  open(unit=100, file='file.txt', status='old', action='read')
  do i=2,n
    read(100,'(*(i1))') imp(i,1:m)
    end do
  close(unit=100)
end subroutine readF

我想知道是否可以读取具有以下内容的文件:

IDs Idx Info
ID001 1 125478521111
ID002 1 525478214147
ID003 2 985550004599
ID004 2 000478520002

结果如下:

ID001 1 1 2 5 4 7 8 5 2 1 1 1 1
ID002 1 5 2 5 4 7 8 2 1 4 1 4 7
ID003 2 9 8 5 5 5 0 0 0 4 5 9 9
ID004 2 0 0 0 4 7 8 5 2 0 0 0 2

第 3 列中的值被吐到 m 列中。

第一行是表头,但我不需要,所以我从第二行开始阅读。

我尝试编写使用以下子程序,但没有成功:

subroutine readF(imp, ind, m, n)
  implicit none
  integer :: n,m,i,imp(n,m),ind(n),chip(n)
  open(unit=100, file='file.txt', status='old', action='read')
  do i=2,n
    read(100,'(i8,i1,*(i1))') ind(i),chip(i),imp(i,1:m)
  end do
  close(unit=100)
end subroutine readF

有谁知道我如何在不手动删除前两列的情况下读取该文件?

谢谢。

【问题讨论】:

  • "i8" 将尝试读取占用八个字符的整数。也许“a8”和一个字符变量会起作用?
  • 我试过了,还是不行。
  • “a8”不起作用,因为第一次迭代是从第一行而不是第二行读取。从 2 开始 i 并不意味着您正在从第 2 行开始阅读。请在我的回答中查看进一步的解释。如果他从第二行开始,“a8”将有效地跳过开头的字符。

标签: fortran gfortran fortran90 fortran77 fortran95


【解决方案1】:

我将猜测每个变量的含义,并尝试解释一些明显的错误。

我相信你的do i=2,n 是一个错误,因为我看到我的一些学生犯了这个错误。从 2 开始 i 并不意味着您正在从第二行读取,它只是 i 的值。然后,假设您有 n 条数据线,您将错过最后一条数据线,因为您正在读取 n-1 条数据线。您想要的是循环之前的空白读取语句。这会跳过标题行。然后你想让 i 从 1 到 n。

从 read 语句中变量的顺序来看,我假设 ind 是 ID 号,chip 是 Idx 号,imp 有 1 个整数的信息编号,每个整数最多 m 个。

您的i8 将获取前 8 列信息并尝试将它们解释为整数。好吧,ID001 1 1 是第一条数据行的前 8 列,这不是整数。您需要跳过“ID”并将“001”读入 ind。然后跳过 1 个字符并将 1 个整数读入芯片,然后再跳过 1 个字符,然后读入 Info,一次 1 个整数。 x 格式说明符跳过 1 个字符。

对于要单独进入 imp 的每个整数,您需要一个从 1 到 m 的隐式 do 循环。我在那里使用了 j 。如果你不知道隐含的 do 循环,请谷歌它。它在 Fortran 中是相当标准的。

这段代码 sn-p 可以做到这一点:

open(unit=100, file='file.txt', status='old', action='read')
read(100,*)  ! This skips the header line.
do i=1,n     ! Read in n data lines.
  read(100,'(2x,i3,1x,i1,1x,*(i1))') ind(i),chip(i),(imp(i,j),j=1,m)
end do
close(unit=100)

解决评论的其他答案。我看你有两个选择。首先,进入行解析。我不会选择这个。

第二个选项是使用未格式化的输入读取行。无格式输入使用空格分隔输入项。我将使第三项成为一个字符变量,其长度足以容纳 m 的长度。这个字符变量可以用 Fortran 的read 语句读取。这称为从内部记录读取。你会像以前一样读取每个整数。这就是它的样子:

character(len=m) :: Info
character(len=:),allocatable :: Dumb
open(unit=100, file='file.txt', status='old', action='read')
read(100,*)  ! This skips the header line.
do i=1,n     ! Read in n data lines.
  read(100,*) Dumb, chip(i), Info
  read(Info,'(*(i1))') (imp(i,j),j=1,m)
end do
close(unit=100)

do 循环中的第一个读取语句是从文件中读取。它将整个第一列粘贴到Dumb 中,无论其长度如何,第二列粘贴到chip(i) 中,并将整个第三列粘贴到一个名为Info 的字符串中。

第二个读取语句是从“内部记录”信息中读取。您可以对字符串使用read 语句。这里我使用格式说明符和隐含的 do 循环一次提取 1 个整数。

【讨论】:

  • 这行得通,谢谢,是的,我理解隐含的 do 循环。顺便说一句,如果第一列是不同长度的字符怎么办。你认为有没有办法在它们之间有空格时读取这 3 列。按照您的方式,第一列必须有 5 个字符。但是,如果一个有 8 个,另一个有 9 个,依此类推。分隔列的唯一因素是它们之间的空间。有可能这样做吗?再次感谢您的详细解释和帮助。
  • 完美,谢谢。我所做的唯一更改是在character(len=*),因为它给了我一个错误Error: Entity with assumed character length at (1) must be a dummy argument or a PARAMETER,因为必须在某处指定这样的长度,但事实并非如此。
猜你喜欢
  • 2023-03-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-09-25
相关资源
最近更新 更多