Fortranで文字列【基礎編その1】
Author: Amasaki Shinobu (雨崎しのぶ)
Twitter: @amasaki203
Posted on: 2025-12-01 JST
次の記事:Fortranで文字列【基礎編その2—文字列の配列】
概要
本稿は「Fortranで文字列」と題したプログラミング解説記事シリーズの第1回である。このシリーズではFortran 2003以降の機能を使ったプログラミングにおける文字列の基本的な取扱い方を見つめなおして、Fortranの真価が再評価されることを目的としている。第1回となるこの記事は基礎編にあたり、リテラルの引用符や変数の使い方、文字列の組込み関数について解説する。
なお、ここではFortranプログラムで扱うcharacter型の表現について、文字(長さ1)と文字列(長さ2以上)を区別せず、すべて文字列と呼ぶ。加えて、配列変数を扱わず、すべてスカラ変数を扱うこととする。つまり変数宣言のdimension属性は扱わない。
文字列の基本的な使い方
文字列リテラル
Fortranプログラムにおいて、文字列をコード上に表現するには、引用符(シングルクォート'またはダブルクォート")で囲った範囲に目的の文字列を記述する。
print *, "hello, world"
print *, 'hello, world' ! これら2つは同一の働きをする
ソースコード中の引用符で囲われた部分は文字列リテラル(規格においては文字定数表現/character
literal
constant)と呼ばれる。print文については次回で扱うが、ここではコンソールに標準出力する機能の文であることを知っていれば十分である。上のコードでは"hello, world"の部分が文字列リテラルにあたる。リテラルとは、ソースコード内において値を直接記述したものであり、上の例では文字列のリテラルなので文字列リテラルと呼ぶ。
引用符を含むリテラル
Fortranではシングルクォートもダブルクォートも同一の働きをする。文字列リテラルの値は、2つのシングルクォートからなる組または2つのダブルクォートからなる組の間に記述する必要がある。つまり'foo'と"foo"は同じ値fooを示す文字列リテラルである。
I'd like to see the menu.のような、値の中に引用符を含む文字列をリテラルとして表現したい場合はどのようにすればよいだろうか。これの解決は単純で、前述の通りシングルクォートとダブルクォートは同じ機能を持つので、ダブルクォートを使って"I'd like to see the menu."と表現すればよい。
次に、He couldn't say "yes".というシングルクォートとダブルクォートを両方含む場合の表現についても考えてみよう。これをコード上で表現するには以下の2つのどちらかの方法を使う:
- 2連引用符を用いる
- 文字列を連結する
2連引用符とは、引用符で囲まれた表現の中で、それと同じ引用符を2つ連続して記述することで、それを引用符1文字の値の表現として使うことができる機能である。これを使えば、'He couldn''t say "yes."'とコードに書いて値He couldn't say "yes."を表現することができる。なお当然であるが、I'd like to see the menu.の例においてもこのアプローチを使って解決することが可能だ。
連結を使ったアプローチは、Fortranで文字列に対して唯一利用可能な組込み演算子//を使う方法である。"He couldn't say " // '"yes."'というようにシングルクォートを含む部分にはダブルクォートで囲み、ダブルクォートを含む部分をシングルクォートで囲んで、それらを連結することで表現できる。
print *, 'He couldn''t say "yes."' ! 2重引用符の方法
print *, "He couldn't say " // '"yes."' ! 文字列連結の方法
文字列型変数
このセクションでは、文字列を格納する変数の扱い方について説明する。
変数の宣言
Fortranにおいて変数を宣言するには型宣言文(type declaration statement)を使用する。
! 固定長文字列変数の宣言
character(8) :: str1
character(len=16) :: str2
! 文字列定数の宣言
character(4), parameter :: para1 = 'hoge'
character(*), parameter :: para2 = 'foobar'
! 文字列の定数はその長さを処理系に任せることができる
様々な宣言文の書き方は次の通り。
character a
character(len=8) b
character(8) c
character*8 d
character e*8, f*8
上の例ではaのみ長さ1の変数、その他のbからfはすべて長さ8の変数の宣言である。可読性と一貫性の観点から、型と属性の後にコロン2つ::を置いて宣言する変数を書くスタイル、つまりstr1またはstr2のような形式の宣言文を用いることを推奨する。
変数の初期値を与えるには、その形式で宣言文を書き、等号に続いてその値を書くことでセットできる。
character :: g = 'g'
character(4) :: h = 'hijk', m = 'mnop'
Fortran
2003以降では、可変長文字列を使用できるようになった。可変長文字列の宣言には、lenパラメータをコロン:にして、allocatable属性を加えて宣言する。
character(:), allocatable :: str3, str4
代入文
プログラムの宣言部で文字列変数を宣言すると、指定した長さ分のメモリが割り当てられ、代入文や入力文によって値を変数に格納することができる。代入文では、等号=を用いて左辺に変数を置き、右辺に別の文字列型変数や文字列リテラルからなる式を置く。入力文は次回以降扱う。
str1 = 'abcdefgh' ! 長さ8の変数に長さ8のリテラルを代入
なお、変数の長さよりも長い値を代入すると、余った部分は切り捨てられ、変数の長さ分だけの値が格納される。一方、変数の長さよりも短い値を代入すると、足りなかった部分はホワイトスペース(半角スペース)で埋められる。
character(6) :: str5, str6
str5 = 'abcdefgh' ! str5に'abcdef'が格納される
str6 = 'abcd' ! str6に'abcd 'が格納される
可変長文字列の場合も同様に代入できる。これを使う場合は、単純に代入するだけで自動的に必要な長さ分の割付けが行われる。
str3 = 'abcdef' ! 長さ6のメモリが割付けされる
同じ変数に再び代入を行うと、上と同様に変数は再割付けされる。
str3 = 'He couldn''t say "yes."'
! 長さ22のメモリが再割付けられて、変数str3にHe couldn't say "yes."が格納される
allocate文を用いて、明示的にメモリ割付けを行うことも可能である。
allocate(character(12) :: str7) ! 長さ12だけ割付ける
! すでに割り付けられている場合にはdeallocate文で一度解放する必要がある
deallocate(str7)
allocate(character(9) :: str7) ! 長さ9だけ割付ける
部分文字列
ここでは部分文字列、つまり文字列変数からその一部を取り出す操作について説明する。
前提として、Fortranのデフォルトの文字列変数は、基本的に1バイト単位でアクセスする。ASCII文字は1文字1バイトとして扱う。また、Fortranのインデックスの取り方は1-basedなので、先頭のインデックスは1となり、末尾のインデックスはその長さに等しい。
部分文字列を取り出すには、変数の直後に括弧の中に、開始インデックスとコロンと終了インデックスを記述する。例えば、変数str8 = 'abcde'の部分文字列bcdを取り出すには、2文字目から4文字目の範囲なのでstr8(2:4)というように書く。
character(5) :: str8 = 'abcde'
print *, str8(1:5) ! abcde
print *, str8(2:4) ! bcd
print *, str8(1:1) ! a
ここで、始点と終点のインデックスを指定すると、その2つの位置に対応する文字を含む形で部分文字列が取り出されることに注意してほしい。また最後の行で示されるとおり、文字列から1文字を取り出す場合にも(1:1)という範囲指定が必要である。
UTF-8などのマルチバイト文字が格納された変数の部分文字列を扱う際には、文字の境界のインデックスを考慮して記述する必要がある。マルチバイト文字については本稿では扱わないが、続く記事で取り上げるつもりである。なおlen関数については次のセクションで解説する。
character(:), allcatable :: str9
str9 = "あいうえお" ! UTF-8では平仮名は1文字3バイト
print *, len(str9) ! 15
print *, str9(4:9) ! いう
print *, str9(1:2) ! -> 正しく表示されない
len関数とlen_trim関数
文字列の長さを知るにはlen関数とlen_trim関数を用いる。使用目的はそれぞれ異なり、len関数は引数に与えた文字列値の長さをそのまま返し、len_trim関数は引数に与えた文字列から末尾のホワイトスペースを取り除いた場合の長さを返す。
print *, len('abcdef ') ! 7
print *, len_trim('abcdef ') ! 6
print *, len_trim(' abcdef') ! 7
固定長の文字列変数にその長さに満たない値を代入した場合には、前述のとおり末尾がホワイトスペースで埋められるので、文字列の実質的な長さを知りたい場合にはlen_trimを多用することになる。一方で、可変長文字列変数に文字列リテラルを代入した際には、右辺の値の長さだけ自動的に割り付けられるのでlen_trimを使わなくてもよい場面が多い。
character(8) :: str10
character(:), allocatable :: str11
str10 = 'abcdef'
str11 = 'abcdef'
print *, len(str10), len_trim(str10) ! 8 6
print *, len(str11), len_trim(str11) ! 6 6
! str10を与えたlen関数は変数str10自体の長さ8を返す
! str11は長さ6で割付けられているので同じ結果を返す
trim関数
文字列変数やリテラルから、末尾の空白を取り除いた部分を取り出すにはtrim関数を用いる。
character(8) :: str12
character(:), allocatable :: str13
str12 = 'abcdef' ! 固定長なので末尾が空白で埋められる
str13 = trim(str12) ! str12の末尾の2つのスペースを取り除いた値を代入する
print *, '"' // str12 // '"' ! "abcdef "
print *, '"' // str13 // '"' ! "abcdef"
まとめ
本稿では、Fortranでの文字列の初歩的な扱い方、リテラルと変数の使い方、部分文字列と組込み関数lenとlen_trimとtrimの3関数の使う方法について述べた。この記事のタイトルに「基礎編その1」とあるように、この続きを書く予定なので、今回扱わなかった、文字列の配列や入出力機能の詳細、文字種別(kind型パラメータ)、その他の組込み手続などの話題についてはその2以降で取り上げたい。
