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)
Provides kind type parameter values.
Definition dc_types.f90:49
integer, parameter, public dp
Double Precision Real number
Definition dc_types.f90:83
integer, parameter, public sp
Single Precision Real number.
Definition dc_types.f90:73