TypechoJoeTheme

MetMan's Blog

网站页面

Fortran字符串处理下篇

MetMan博 主
2023-10-21
/
0 评论
/
152 阅读
/
1017 个字
/
百度已收录
10/21
本文最后更新于 2024年08月03日,已超过 48天没有更新。如果文章内容或图片资源失效,请留言反馈,我会及时处理,谢谢!

字符与数值类型转换

通过ASCII表转换

常用的字符与整数一一映射的编码表是ASCII表,规定了256个字符与0-255整数一一对应关系。

下表是Fortran用于两者互相转换的内置函数,其中ACHAR与CHAR、IACHAR与ICHAR区别在于一个指定使用ASCII表,另一个是处理器使用的编码表,不一定是ASCII表。但通常两者是等价的。

内置过程名功能
ACHAR(I)返回整数对应的ASCII码表中字符
CHAR(I,[,KIND])返回给定整数对应的处理器使用的编码序列字符
IACHAR(C)返回ASCII表中字符对应的十进制整数
ICHAR(C)返回处理器使用的编码表中字符对应的整数

ASCII码表中字符A-Z、a-b、0-9都是有序、连续排列的,利用这个特点我们可以对字符串进行大小比较、大小写转换等操作。

下面示例程序实现了一个转换大写字符串的功能。

module string_utils
  implicit none
contains
  function to_upper(str)
    implicit none
    character(len=*),intent(in)  :: str
    character(len=len(str))      :: to_upper
    integer :: i,char2i

    do i = 1, len(str)
      char2i = iachar(str(i:i))
      if (char2i >= 97 .and. char2i <= 122) then
        to_upper(i:i) = achar(char2i - 32) !大小写字母相差ASCII十进制 32
      else
        to_upper(i:i) = str(i:i)
      endif
    enddo

  end function to_upper
end module string_utils

program test
  use string_utils
  implicit none
  character(len=24) :: str_in,str_out

  str_in = "ABCadc099DEF"
  str_out = to_upper(str_in)
  print*, "str_out = ",str_out
end

Fortran与C字符串区别

C字符串有null字符’\0’作为字符串的结尾符,而Fortran不需要。因此,Fortran与C混编时,Fortran字符串传给C函数需要加上结尾符string // char(0)

字符串与数值类型转换

我们从文本文件中读入数值型数据及将数据写入文本文件都会有一个隐式的类型转换,在文本文件中都是字符形式存储,而在内存中可以是整型、实型数据,编译器调用内部函数进行了隐式类型转换。

如果我们需要自己显式类型转换,比如我想将关于日期时间的年、月、日等整型变量组成一个字符串变量用于文件名的一部分。我们可以使用Fortran中“Internal file”功能,想象有一个内部文本文件存放在内存中(而不是磁盘上),将数据写入这个文件就完成了数值类型到字符串的转换,反之从内部文件读入则可以将字符串转换为数值类型。

  character*10  :: cdate
  integer       :: iyear,imon,iday
  
  iyear =  2022
  imon  =  7
  iday  =  21
  write(cdate, '(I4.4,A1,I2.2,A1,I2.2)') iyear,'-',imon,'-',iday

  print*, 'cdate=',cdate

删除字符串空格

一般我们声明字符串变量长度时不会完全与实际占有长度相同,多出来的空间一般会用空格占据,但处理字符串过程中往往需要删除这些空格,我们可以使用以下内置函数。

内置过程名功能
ADJUSTL(STRING)字符串左对齐,即去除左端空格
ADJUSTR(STRING)字符串右对齐,即去除右端空格
TRIM(STRING)去除字符串尾部空格

通过以下程序来查看三个函数的区别。

  character*128 :: str3

  str3 = '       hello, fortran     '
  print*, 'BEG',str3,'END'
  print*, 'BEG',trim(str3),'END'
  print*, 'BEG',adjustl(str3),'END'
  print*, 'BEG',adjustr(str3),'END'

注意对齐函数虽然将其中一端的空格去除,但会在另一端补上空格。因此对于一个两端都有空格的路径字符串变量,需要配合trim函数去除两端空格。

  filename = '     /home/username/a.txt     '
  open(99, file=trim(adjustl(filename)), ...)

计算字符长度

计算字符串变量长度也是常见操作。

内置过程名功能
LEN计算字符串长度
LEN_TRIM(STRING)计算去掉尾部空格的字符长度

两个字符长度计算函数常用于对字符串变量遍历操作。

character(len=128) :: str 

do i = 1, len(str)
  str(i:i) = char(i)
enddo

同时两个函数是在编译时执行(compile-time),因此能够用于字符串变量声明,可以用于声明与传入字符串参数相同长度的字符变量。

subroutine length(str1)
  implicit none
  character(len=*)              :: str1
  character(len=len(str1))      :: str2
  character(len=len_trim(str1)) :: str3

  print*, 'len(str1) = ', len(str1)
  print*, 'len(str2) = ', len(str2)
  print*, 'len(str3) = ', len(str3)
end subroutine length

program main
  implicit none
  character(len=16) :: str1

  str1 = '0123456789'

  call length(str1)
end

字符串匹配

内置过程名功能
INDEX(string,substring)substring在string中第一个匹配的开始位置,不匹配返回0

可以增加可选参数BACK并设为.TRUE. ,返回最后一个匹配结果的开始位置。这个功能可以用于从一个包含路径的文件名变量中获取dirname或者basename,匹配最后一个'/’路径分隔符即可。

下面是使用index功能进行大小写字符转换另一种实现(摘自stdlib_ascii)

character(len=*),parameter :: uppercase = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
character(len=*),parameter :: lowercase = "abcdefghijklmnopqrstuvwxyz"
character(len=1) :: c

k = index(uppercase, c)
if(k > 0) then
  t = lowercase(k:k)
else 
  t = c
endif

一个实际的例子是WRF后处理软件ARWpost中处理指定气象场。
变量plot_these_fields值通过namelist文件指定

fields = 'height,geopt,theta,tc,tk,td,td2'

代码中用index函数确定某个气象场是否在这个字符串里来决定是否处理该气象场。

IF (INDEX(plot_these_fields, ",pressure," /= 0))THEN
   ...
ENDIF

IF (INDEX(plot_these_fields, ",geopt," /= 0))THEN
   ...
ENDIF
朗读
赞(0)
赞赏
感谢您的支持,我会继续努力哒!
版权属于:

MetMan's Blog

本文链接:

https://blog.metman.top/index.php/archives/12/(转载时请注明本文出处及文章链接)

评论 (0)

互动读者

标签云

最新回复

暂无回复

登录
X
用户名
密码