Loading...
Searching...
No Matches
dcstringsprintf.f90
Go to the documentation of this file.
1!== Formatted output conversion
2!
3! Authors:: Yasuhiro MORIKAWA, Eizi TOYODA
4! Version:: $Id: dcstringsprintf.f90,v 1.2 2009-03-20 09:50:19 morikawa Exp $
5! Tag Name:: $Name: $
6! Copyright:: Copyright (C) GFD Dennou Club, 2000-2005. All rights reserved.
7! License:: See COPYRIGHT[link:../../COPYRIGHT]
8!
9!== Overview
10!
11! C の sprintf(3) のように文字列をフォーマットして返します。
12! ただし、実装は C の sprintf(3) とは大分違うのでご注意ください。
13!
14!== Formatter
15!
16! dc_string#CPrintf, dc_string#Printf のフォーマット引数に
17! 用いられる指示子は <b><tt>%</tt></b> で始まります。種類は
18! 以下の通りです。
19!
20! <b><tt>指示子</tt></b> ::
21! <tt>対応する引数</tt> :: データの種類と出力形式
22!
23! <b><tt>%d, %D</tt></b> ::
24! <tt>i(:)</tt> :: 整数データ (10 進数) を表示.
25! %2d や %04d のように'%' の後ろに数字を指定することで
26! 出力する桁数を変更できます.
27! '%' の直後が 0 の場合は先頭に 0 を, そうでない場合は空白を埋めます.
28!
29! <b><tt>%o, %O</tt></b> ::
30! <tt>i(:)</tt> :: 8 進数データを表示
31!
32! <b><tt>%x, %X</tt></b> ::
33! <tt>i(:)</tt> :: 16 進数データを表示
34!
35! <b><tt>%f, %F</tt></b> ::
36! <tt>d(:)</tt> :: 倍精度実数データを最大全桁数 80、小数部の桁数 40で表示
37!
38! <b><tt>%r, %R</tt></b> ::
39! <tt>r(:)</tt> :: 単精度実数データを最大全桁数 80、小数部の桁数 40で表示
40!
41! <b><tt>%b, %B</tt></b> ::
42! <tt>L(:)</tt> :: 論理データを 真:T、偽:F で表示
43!
44! <b><tt>%y, %Y</tt></b> ::
45! <tt>L(:)</tt> :: 論理データを 真:yes、偽:no で表示
46!
47! <b><tt>%c, %C</tt></b> ::
48! <tt>c1、c2、c3</tt> :: 文字データ (変数)
49!
50! <b><tt>%a, %A</tt></b> ::
51! <tt>ca</tt> :: 文字データ (配列)
52!
53!
54! 文字データ (変数) 以外は、1つの型のデータをいくつでも与えることが可能です。
55! 文字データ (変数) は c1、c2、c3 にそれぞれ 1
56! つづつの文字データしか与えることができません。
57! +ca+ 引数を用いる場合は dc_string#StoA を併用すると便利です。
58!
59! また、フォーマット指定子として <b><tt>%*</tt></b> を与えることで、
60! 複数のデータを一度に出力することも可能です。
61! その場合、いくつのデータを一度に出力するかを <tt>n(:)</tt>
62! に与える必要があります。
63!
64!== Example
65!
66!=== dc_string#CPrintf を用いた出力の例
67!
68! use dc_types, only: STRING
69! use dc_string, only: CPrintf
70! character(len = STRING) :: output, color="RED", size="Large"
71! integer, parameter :: n1 = 2, n2 = 3
72! integer :: int = 10, arrayI1(n1), arrayI2(n2), i
73! real :: arrayR(n1)
74! logical :: eq
75!
76! do i = 1, n1
77! arrayI1(i) = 123 * i ; arrayR(i) = 1.23 * i
78! enddo
79! do i = 1, n2
80! arrayI2(i) = 345 * i
81! enddo
82! eq = (maxval(arrayI1) == minval(arrayI2))
83! output = CPrintf(fmt="color=%c size=%c int=%03d I1=%*d I2=%*04d R=%*r equal=%y", &
84! & c1=trim(color), c2=trim(size), i=(/int, arrayI1, arrayI2/), &
85! & r=(/arrayR/), L=(/eq/), n=(/n1, n2, n1/))
86!
87! write(*,*) trim(output)
88!
89! 文字データ以外のものは基本的に1次元配列しか引数にとれないため、
90! 多次元配列を出力したい場合には組込み関数である pack 関数を
91! 用いると良いでしょう。以下にその例を記します。
92!
93! use dc_types, only: STRING
94! use dc_string, only: CPrintf
95! character(len = STRING) :: output
96! integer :: i,j,k
97! integer, parameter :: n1 = 2, n2 = 3, n3 = 4
98! real :: array(n1,n2,n3)
99!
100! do i = 1, n1
101! do j = 1, n2
102! do k = 1, n3
103! array(i,j,k) = i * 0.1 + j * 1.0 + k * 10.0
104! enddo
105! enddo
106! enddo
107! output = CPrintf('array=<%*r>', &
108! & r=(/pack(array(:,:,:), .true.)/), n=(/size(array(:,:,:))/))
109! write(*,*) trim(output)
110!
111!=== dc_string#Printf を用いた出力の例
112!
113! use dc_types, only: STRING
114! use dc_string, only: Printf
115! character(len = STRING) :: output, color="RED", size="Large"
116! integer, parameter :: n1 = 2, n2 = 3
117! integer :: int = 10, arrayI1(n1), arrayI2(n2), i
118! real :: arrayR(n1)
119! logical :: eq
120!
121! do i = 1, n1
122! arrayI1(i) = 123 * i ; arrayR(i) = 1.23 * i
123! enddo
124! do i = 1, n2
125! arrayI2(i) = 345 * i
126! enddo
127! eq = (maxval(arrayI1) == minval(arrayI2))
128!
129! ! 装置番号 6 (標準出力) に直接出力する場合
130! call Printf(unit=6, &
131! & fmt="color=%c size=%c int=%03d I1=%*d I2=%*04d R=%*r equal=%y", &
132! & c1=trim(color), c2=trim(size), i=(/int, arrayI1, arrayI2/), &
133! & r=(/arrayR/), L=(/eq/), n=(/n1, n2, n1/))
134!
135! ! 文字列 output に渡す場合
136! call Printf(unit=output, &
137! & fmt="color=%c size=%c int=%03d I1=%*d I2=%*04d R=%*r equal=%y", &
138! & c1=trim(color), c2=trim(size), i=(/int, arrayI1, arrayI2/), &
139! & r=(/arrayR/), L=(/eq/), n=(/n1, n2, n1/))
140! write(*,*) trim(output)
141
142
143subroutine dcstringsprintf(unit, fmt, i, r, d, L, n, c1, c2, c3, ca)
144 !
145 ! フォーマット文字列 fmt に従って変換された文字列を unit に返します。
146 ! 第2引数 fmt には指示子を含む文字列を与えます。
147 ! 指示子には「<tt>%</tt>」を用います。
148 ! <tt>%</tt> を用いたい場合は 「<tt>%%</tt>」と記述します。
149 ! 指示子および用例に関しての詳細は dc_utils/dcstringsprintf.f90 を参照ください。
150 !
151 use dc_types, only: sp, dp
152 implicit none
153 character(*), intent(out) :: unit
154 character(*), intent(in) :: fmt
155 integer, intent(in), optional :: i(:), n(:)
156 real(SP), intent(in), optional :: r(:)
157 real(DP), intent(in), optional :: d(:)
158 logical, intent(in), optional :: L(:)
159 character(*), intent(in), optional :: c1, c2, c3
160 character(*), intent(in), optional :: ca(:)
161
162 ! 上記配列引数のカウンタ
163 integer :: ni, nr, nd, nl, nc, na, nn
164 integer :: ucur ! unit に書かれた文字数
165 integer :: endp ! 既に処理された fmt の文字数
166 integer :: cur ! 現在着目中の文字は fmt(cur:cur) である
167 integer :: ptr ! fmt から検索をするときに使用
168 integer :: exp_ptr ! fmt から数値の指数部を検索をするときに使用
169 integer :: minus_ptr ! '-' を検索する時に使用
170 integer :: repeat ! %数字 または %* から決定された繰返し数
171 integer :: m ! 1:repeat の範囲で動くループ変数
172 integer :: stat ! エラー処理
173 character(80) :: cbuf ! read/write 文のバッファ
174 character(80) :: exp_buf ! real/write 文の指数部のバッファ (実数型用)
175 character(80) :: ibuf ! real/write 文のバッファ (整数型用)
176 integer :: len_ibuf ! ibuf の長さ
177 integer :: figs_ibuf ! ibuf の有効な桁数
178 logical :: int_zero_fill ! 先頭を 0 で埋めるかどうかを判定するフラグ (整数型用)
179 integer :: int_figs ! 整数型を出力する際の桁数 (整数型用)
180 continue
181 ni = 0; nr = 0; nd = 0; nl = 0; nc = 0; na = 0; nn = 0
182 unit = ""
183 ucur = 0
184 endp = 0
185 int_figs = 0
186 int_zero_fill = .false.
187 mainloop: do
188 cur = endp + 1
189 if (cur > len(fmt)) exit mainloop
190 !
191 ! リテラルに転写できる文字列 fmt(cur:endp-1) を発見処理
192 !
193 endp = cur - 1 + scan(fmt(cur: ), '%')
194 if (endp > cur) then
195 call append(unit, ucur, fmt(cur:endp-1), stat)
196 if (stat /= 0) exit mainloop
197 else if (endp == cur - 1) then
198 call append(unit, ucur, fmt(cur: ), stat)
199 exit mainloop
200 endif
201 !
202 ! % から書式指定文字までを fmt(cur:endp) とする
203 !
204 cur = endp + 1
205 endp = cur - 1 + scan(fmt(cur: ), 'DdOoXxFfRrBbYySsCcAa%')
206 if (endp < cur) then
207 call append(unit, ucur, fmt(cur-1: ), stat)
208 exit mainloop
209 endif
210 cbuf = fmt(cur:endp-1)
211 !
212 ! %* がある場合、n(:) に渡された数から繰り返し回数を取得
213 !
214 if (cbuf(1:1) == '*') then
215 nn = nn + 1
216 if (nn > size(n)) then
217 repeat = 1
218 else
219 repeat = n(nn)
220 endif
221 ibuf = cbuf(2:)
222 else
223 repeat = 1
224 ibuf = cbuf
225! else if (cbuf == '') then
226! repeat = 1
227! else
228! ptr = verify(cbuf, " 0123456789")
229! if (ptr > 0) cbuf(ptr: ) = " "
230! read(cbuf, "(I80)", iostat=ptr) repeat
231 endif
232 !
233 ! %2d や %04d のように '%' の後ろに数字が指定され、
234 ! かつ d (整数型変数の表示) の場合には先頭に空白
235 ! または 0 を埋める.
236 !
237 if (scan(ibuf(1:1),'1234567890') > 0) then
238 if (ibuf(1:1) == '0') then
239 int_zero_fill = .true.
240 else
241 int_zero_fill = .false.
242 end if
243 read(unit=ibuf, fmt="(i80)") int_figs
244 else
245 int_figs = 0
246 int_zero_fill = .false.
247 endif
248 percentrepeat: do m = 1, repeat
249 if (m > 1) then
250 call append(unit, ucur, ", ", stat)
251 if (stat /= 0) exit mainloop
252 endif
253 select case(fmt(endp:endp))
254 case('d', 'D')
255 if (.not. present(i)) cycle mainloop
256 ni = ni + 1; if (ni > size(i)) cycle mainloop
257 write(ibuf, "(i20)") i(ni)
258 len_ibuf = len(trim(adjustl(ibuf)))
259 figs_ibuf = verify(ibuf, ' ')
260 cbuf = ' '
261 if (int_figs > len_ibuf) then
262 minus_ptr = scan(ibuf, '-')
263 if (int_zero_fill) then
264 if (minus_ptr /= 0) then
265 len_ibuf = len_ibuf - 1
266 figs_ibuf = figs_ibuf + 1
267 cbuf(1:int_figs-len_ibuf) = '-0000000000000000000'
268 else
269 cbuf(1:int_figs-len_ibuf) = '00000000000000000000'
270 end if
271 end if
272 cbuf(int_figs-len_ibuf+1:) = ibuf(figs_ibuf:20)
273 else
274 cbuf = ibuf(figs_ibuf:20)
275 end if
276 call append(unit, ucur, trim(cbuf), stat)
277 if (stat /= 0) exit mainloop
278 case('o', 'O')
279 if (.not. present(i)) cycle mainloop
280 ni = ni + 1; if (ni > size(i)) cycle mainloop
281 write(cbuf, "(o20)") i(ni)
282 call append(unit, ucur, trim(adjustl(cbuf)), stat)
283 if (stat /= 0) exit mainloop
284 case('x', 'X')
285 if (.not. present(i)) cycle mainloop
286 ni = ni + 1; if (ni > size(i)) cycle mainloop
287 write(cbuf, "(z20)") i(ni)
288 call append(unit, ucur, trim(adjustl(cbuf)), stat)
289 if (stat /= 0) exit mainloop
290 case('f', 'F')
291 if (.not. present(d)) cycle mainloop
292 nd = nd + 1; if (nd > size(d)) cycle mainloop
293 write(cbuf, "(f80.40)") d(nd)
294 cbuf = adjustl(cbuf)
295 exp_ptr = verify(cbuf, ' 1234567890-+.', back=.true.)
296 exp_buf = ' '
297 if (exp_ptr > 0) then
298 exp_buf = cbuf(exp_ptr: )
299 cbuf(exp_ptr: ) = " "
300 end if
301 ptr = verify(cbuf, " 0", back=.true.)
302 if (ptr > 0) cbuf(ptr+1: ) = " "
303 cbuf = trim(cbuf) // trim(exp_buf)
304 call append(unit, ucur, trim(adjustl(cbuf)), stat)
305 if (stat /= 0) exit mainloop
306 case('r', 'R')
307 if (.not. present(r)) cycle mainloop
308 nr = nr + 1 ; if (nr > size(r)) cycle mainloop
309 write(cbuf, "(f80.40)") r(nr)
310 cbuf = adjustl(cbuf)
311 exp_ptr = verify(cbuf, ' 1234567890-+.', back=.true.)
312 exp_buf = ' '
313 if (exp_ptr > 0) then
314 exp_buf = cbuf(exp_ptr: )
315 cbuf(exp_ptr: ) = " "
316 end if
317 ptr = verify(cbuf, " 0", back=.true.)
318 if (ptr > 0) cbuf(ptr+1: ) = " "
319 cbuf = trim(cbuf) // trim(exp_buf)
320 call append(unit, ucur, trim(adjustl(cbuf)), stat)
321 if (stat /= 0) exit mainloop
322 case('b', 'B')
323 if (.not. present(l)) cycle mainloop
324 nl = nl + 1; if (nl > size(l)) cycle mainloop
325 write(cbuf, "(L1)") l(nl)
326 call append(unit, ucur, trim(adjustl(cbuf)), stat)
327 if (stat /= 0) exit mainloop
328 case('y', 'Y')
329 if (.not. present(l)) cycle mainloop
330 nl = nl + 1; if (nl > size(l)) cycle mainloop
331 if (l(nl)) then
332 call append(unit, ucur, "yes", stat)
333 if (stat /= 0) exit mainloop
334 else
335 call append(unit, ucur, "no", stat)
336 if (stat /= 0) exit mainloop
337 endif
338 case('c', 'C')
339 nc = nc + 1
340 if (nc == 1) then
341 if (.not. present(c1)) cycle percentrepeat
342 call append(unit, ucur, c1, stat)
343 if (stat /= 0) exit mainloop
344 else if (nc == 2) then
345 if (.not. present(c2)) cycle percentrepeat
346 call append(unit, ucur, c2, stat)
347 if (stat /= 0) exit mainloop
348 else if (nc == 3) then
349 if (.not. present(c3)) cycle percentrepeat
350 call append(unit, ucur, c3, stat)
351 if (stat /= 0) exit mainloop
352 endif
353 case('a', 'A')
354 if (.not. present(ca)) cycle mainloop
355 na = na + 1; if (na > size(ca)) cycle mainloop
356 call append(unit, ucur, trim(adjustl(ca(na))), stat)
357 if (stat /= 0) exit mainloop
358 case('%')
359 call append(unit, ucur, '%', stat)
360 if (stat /= 0) exit mainloop
361 end select
362 enddo percentrepeat
363 enddo mainloop
364 return
365contains
366
367 subroutine append(unitx, ucur, val, stat)
368 !
369 ! unitx に val を付加。その際、unitx がその最大文字列長を越えた場合
370 ! には stat = 2 を返す。
371 !
372 character(*), intent(inout):: unitx ! 最終的に返される文字列
373 integer, intent(inout):: ucur ! unitx の文字数
374 character(*), intent(in) :: val ! unitx に付加される文字列
375 integer, intent(out) :: stat ! ステータス
376 integer :: wrsz ! val の文字列
377 continue
378 ! unitx の最大長を越えた場合には stat = 2 を返す。
379 if (ucur >= len(unitx)) then
380 stat = 2
381 ! 正常時の処理
382 else
383 ! unitx の長さを越えた場合も考慮して unitx に val を付加する。
384 wrsz = min(len(val), len(unitx) - ucur)
385 unitx(1+ucur: wrsz+ucur) = val(1: wrsz)
386 ucur = ucur + wrsz
387 stat = 0
388 if (wrsz < len(val)) stat = 1
389 endif
390 end subroutine append
391
392end subroutine dcstringsprintf
subroutine append(unitx, ucur, val, stat)
subroutine dcstringsprintf(unit, fmt, i, r, d, l, n, c1, c2, c3, ca)
種別型パラメタを提供します。
Definition dc_types.f90:49
integer, parameter, public dp
倍精度実数型変数
Definition dc_types.f90:83
integer, parameter, public sp
単精度実数型変数
Definition dc_types.f90:73