用逗号分割长度未知但子字符串格式已知的 Fortran 字符串?

Posted

技术标签:

【中文标题】用逗号分割长度未知但子字符串格式已知的 Fortran 字符串?【英文标题】:Split Fortran character string of unknown length but known substring format by commas? 【发布时间】:2017-12-10 19:21:15 【问题描述】:

我正在尝试用逗号将输入变量拆分为一些 Fortran 代码。该变量是一个字符串,其中包含可变数量的日期,但日期始终采用 DD-MMM-YYYY 格式。

这样的字符串的一个例子:

04-DEC-2015,10-DEC-2015,23-DEC-2015,25-DEC-2015

它并不总是四个日期,但它始终是该格式的 11 个字符的日期。

我只想将这些日期打印在不同的行上;当前代码:

write(outfile,10) '     - ', TRIM(days)

打印:

     -  04-DEC-2015,10-DEC-2015,23-DEC-2015,25-DEC-2015

我想写一些打印出来的东西:

     -  '04-DEC-2015'
     -  '10-DEC-2015'
     -  '23-DEC-2015'
     -  '25-DEC-2015'

有没有一种简单的方法来做到这一点(我对 Fortran 很陌生)?我正在考虑计算字符串中的逗号数,加 1 以获得日期数,并在循环中创建一个适合每个日期的 CHARACTER(11) 变量,一次从字符串中获取 11 个字符(跳过逗号) ,并以我想要的格式打印该日期。是不是太复杂了?

【问题讨论】:

【参考方案1】:

正如之前所建议的,从内部文件中以列表为导向的读取将无需更多努力就可以处理逗号分割。对于

character(11) :: split_days(MAX_DAYS)=''
ndays = ...
read(days,*) split_days(1:ndays)

为了工作,我们需要知道ndays 的值。如果你对类似的东西感到满意

ndays = (len_trim(days)+1)/12
ndays = INDEX(days,',',BACK=.TRUE)/12+1

ndays = COUNT([(days(i:i),i=1,LEN_DAYS)].eq.',')+1

那么一切都很好。

或者,你可以有一个可分配的数组

character(11), allocatable :: split_days(:)
ndays = ...
allocate (split_days(ndays))
read(days,*) split_days

或者,您不需要读取内部文件(列表导向或其他方式),但如果我相信输入数据的形式,我可能会这样做。

do i=1,MAX_DAYS
  split_days(i)=days(12*(i-1)+1:)
  if (INDEX(days(12*i:),',').eq.0) exit
end do

列表导向读取方法的另一种可能性是选择大量读取,如果失败,则再次尝试读取更少。这仅在更棘手的情况下才有意义。

最后,如果需要,您可以使用通常的数组缩小/增长技巧。


如果您只是在打印而不是存储之后,那么上面的循环方法可以避免弄乱一个未知长度的数组:

do i=1,MAX_DAYS
  print '("     - ''",A11,"''")', days(12*(i-1)+1:)
  if (INDEX(days(12*i:),',').eq.0) exit
end do

【讨论】:

read(days,*) split_days(1:ndays) read(days,*) split_days)。谢谢。【参考方案2】:

使用内部读取。

 character(len=47) :: in = '04-DEC-2015,10-DEC-2015,23-DEC-2015,25-DEC-2015'
 character(len=11) :: out(4)
 read(in,*)out

请注意,这是用逗号分隔的。如果逗号之间的字符串多于或少于 11 个字符,它们将被截断或填充空白。另请注意,字符串中不能有空格,否则 read 也会在那里拆分。

您确实需要知道要阅读多少。如果你知道它们的长度都是 11,你可以使用 (len(in)+1)/12 ,或者使用 index 来计算逗号。

【讨论】:

我是按照这些思路思考的,但请注意日期的数量是可变的。无论如何,OP都必须计算一些东西。当我尝试完全实现这一点时,它最终比最初提出的 OP 解决方案更加复杂。 我的意思是计算填充了多少个数组元素,但是如果你将它分配到正确的长度,它最终会起作用(以避免出现空行)。 这很棒,如果我知道天数就可以了。就像你说的,如果我设置 character(len=11)::out(4) 它可以工作,但是我需要那个 4 是一个变量,比如 p,如果我尝试设置 character(len=11)::out (p) 在计算 p = (len(in)+q)/12 后,它给了我一个“A specification statement cannot appear in the executable section”。编译时出错。知道如何在 计算缺失日期的数量之后设置 out 的大小吗? @vladimir -f 我可以在代码的规范部分设置 character(11) :: out(31) 之后再减小 out 的大小吗?我不会有超过 31 个日期,如果我可以将可执行部分中的 31 的大小缩减为 4(或 p 的任何计算值),则 read(in,*)out 有效。否则,如果 out 的大小保持为 31,则不会打印任何内容。 更明确地说,我认为您可以将out 声明为character(11) :: out(31),获取项目数为p = (len_trim(in)+1)/12(假设没有空格)和read(in,*) out( 1 : p )(即,读入子数组)。或者,我们可以将“out”声明为character(11), allocatable :: out(:),将其分配为allocate( out( p ) ),然后是read(in,*) out(这里不需要索引,因为out 大小合适)。但是后一种方法可能需要重新分配out(当in具有不同数量的项目时),所以第一种方法可能更方便。

以上是关于用逗号分割长度未知但子字符串格式已知的 Fortran 字符串?的主要内容,如果未能解决你的问题,请参考以下文章

将未知长度的字符串与已知长度的字符串进行比较

重写 NOT IN,但子查询涉及逗号分隔的字符串 (ID)

合并流以及已知文件流长度和未知文件长度的文件流读取方法

Java 以逗号分割的字符串数据取出来,逗号前面的字符

用逗号分割字符串,但忽略括号或引号中的逗号

根据空格和逗号分割输入字符串