1 | /*! |
---|
2 | @file Include/Classes/ActiveBasic/Strings/SPrintF.ab |
---|
3 | @brief SPrintfとその補助ルーチンが含まれるファイル。 |
---|
4 | |
---|
5 | SPrintfで数値変換が行われるとき、呼出の階層は、 |
---|
6 | SPrintf→FormatInteger, FormatFloat→FormatIntegerEx, FormatFloatExとなる。 |
---|
7 | |
---|
8 | また、次のような変換ルーチンが存在する。 |
---|
9 | @li FormatFloatE |
---|
10 | @li FormatFloatF |
---|
11 | @li FormatFloatG |
---|
12 | @li FormatFloatA |
---|
13 | @li FormatIntegerD |
---|
14 | @li FormatIntegerU |
---|
15 | @li FormatIntegerO |
---|
16 | @li FormatIntegerX |
---|
17 | @li FormatCharacter |
---|
18 | @li FormatString |
---|
19 | */ |
---|
20 | |
---|
21 | Namespace ActiveBasic |
---|
22 | Namespace Strings |
---|
23 | |
---|
24 | Namespace Detail |
---|
25 | |
---|
26 | /*! |
---|
27 | @brief 浮動小数点数を文字列化する低水準な関数。符号、指数、仮数に分けて出力。 |
---|
28 | @author Egtra |
---|
29 | @date 2007/09/18 |
---|
30 | @param[in] x 文字列化する浮動小数点数 |
---|
31 | @param[out] e 指数 |
---|
32 | @param[out] sign 符号 |
---|
33 | @return 仮数 |
---|
34 | 仮数は1の位から下へ17桁で、小数点を含まない。そのため、誤差を無視すればVal(仮数) * 10 ^ (e - 17) = Abs(x)が成り立つ。 |
---|
35 | |
---|
36 | xに無限大、非数を渡した場合の動作は未定義。 |
---|
37 | */ |
---|
38 | Function FloatToChars(x As Double, ByRef e As Long, ByRef sign As Boolean) As String |
---|
39 | Imports System |
---|
40 | |
---|
41 | '0を弾く |
---|
42 | If x = 0 Then |
---|
43 | If GetQWord(VarPtr(x) As *QWord) And &h8000000000000000 Then |
---|
44 | sign = True |
---|
45 | Else |
---|
46 | sign = False |
---|
47 | End If |
---|
48 | |
---|
49 | e = 0 |
---|
50 | FloatToChars = "00000000000000000" |
---|
51 | Exit Function |
---|
52 | End If |
---|
53 | |
---|
54 | '符号の判断(同時に符号を取り除く) |
---|
55 | If x < 0 Then |
---|
56 | sign = True |
---|
57 | x = -x |
---|
58 | Else |
---|
59 | sign = False |
---|
60 | End If |
---|
61 | |
---|
62 | '1e16 <= x < 1e17へ正規化 |
---|
63 | '(元のx) = (正規化後のx) ^ (d - 17)である。 |
---|
64 | Dim d = Math.Floor(Math.Log10(x)) As Long |
---|
65 | If d < 16 Then |
---|
66 | x *= ipow(10, +17 - d) |
---|
67 | ElseIf d > 16 Then |
---|
68 | x /= ipow(10, -17 + d) |
---|
69 | End If |
---|
70 | |
---|
71 | '補正 |
---|
72 | While x < 1e16 |
---|
73 | x *= 10 |
---|
74 | d-- |
---|
75 | Wend |
---|
76 | While x >= 1e17 |
---|
77 | x /= 10 |
---|
78 | d++ |
---|
79 | Wend |
---|
80 | |
---|
81 | d-- |
---|
82 | e = d |
---|
83 | |
---|
84 | FloatToChars = FormatIntegerLU((x As Int64) As QWord, 17, 0, None) |
---|
85 | End Function |
---|
86 | |
---|
87 | /*! |
---|
88 | @brief 書式化関数群で使用するフラグ。 |
---|
89 | @author Egtra |
---|
90 | @date 2007/09/18 |
---|
91 | */ |
---|
92 | Const Enum FormatFlags |
---|
93 | '! 何も指定がない。 |
---|
94 | None = &h0 |
---|
95 | /*! |
---|
96 | 符号、+。符号付変換[diAaEeFfGg]のとき、正の値でも符号を付ける。 |
---|
97 | AdjustFieldWidthの仕様から、Format関数郡内からAdjustFieldWidthにかけて、 |
---|
98 | 単に数値が符号付である(負の値である)ことを示す意味でも用いられる。 |
---|
99 | */ |
---|
100 | Sign = &h1 |
---|
101 | /*! 空白、空白文字。 |
---|
102 | 符号付変換[diAaEeFfGg]のとき、正の値ならば符号分の空白を開ける。Signが立っているときには無視される。 |
---|
103 | */ |
---|
104 | Blank = &h2 |
---|
105 | /*! ゼロ、0。 |
---|
106 | [diouXxAaEeFfGg]で、フィールドの空きを0で埋める。leftが立っているときには無視される。 |
---|
107 | */ |
---|
108 | Zero = &h4 |
---|
109 | '! 左揃え、-。フィールド内で左揃えにする。 |
---|
110 | LeftSide = &h8 |
---|
111 | /*! 代替表記、#。 |
---|
112 | @li [OoXx]では、値が0でない場合、先頭に0、0xを付ける。</ul> |
---|
113 | @li [AaEeFfGg]では、精度0でも小数点を付ける。</ul> |
---|
114 | @li [Gg]では、それに加え、小数部末尾の0の省略を行わないようにする。</ul> |
---|
115 | */ |
---|
116 | Alt = &h10 |
---|
117 | '! 大文字。使用するアルファベットを大文字にする。[aefgx]を[AEFGX]化する。 |
---|
118 | Cap = &h20 |
---|
119 | |
---|
120 | '!BASIC接頭辞。&h, &oなど。 |
---|
121 | BPrefix = &h40 |
---|
122 | |
---|
123 | /*! |
---|
124 | 内部処理用に予約。 |
---|
125 | @note Minusとして使用されている。 |
---|
126 | */ |
---|
127 | Reserved = &h80000000 |
---|
128 | End Enum |
---|
129 | |
---|
130 | /*! |
---|
131 | @brief 浮動小数点数をprintfの%e, %E(指数形式、十進法)相当の変換で文字列化する関数。 |
---|
132 | @author Egtra |
---|
133 | @date 2007/09/18 |
---|
134 | @param[in] x 文字列化する浮動小数点数値。 |
---|
135 | @param[in] precision 精度。小数点以下の桁数。DWORD_MAXのとき、指定なしとして既定値6となる。 |
---|
136 | @param[in] field フィールド幅。 |
---|
137 | @param[in] flags 書式フラグ。 |
---|
138 | @return xの文字列表現 |
---|
139 | */ |
---|
140 | Function FormatFloatE(x As Double, precision As DWord, field As DWord, flags As FormatFlags) As String |
---|
141 | FormatFloatE = FormatFloatEx(AddressOf(FormatFloatE_Convert), x, precision, field, flags) |
---|
142 | End Function |
---|
143 | |
---|
144 | /* |
---|
145 | @brief 浮動小数点数をprintfの%e, %E(指数形式、十進法)相当の変換で文字列化する関数。 |
---|
146 | @author Egtra |
---|
147 | @date 2008/03/08 |
---|
148 | @param[in,out] sb 書式化した文字列を追加するバッファ。 |
---|
149 | @param[in] x 文字列化する浮動小数点数値。 |
---|
150 | @param[in] precision 精度。小数点以下の桁数。DWORD_MAXのとき、指定なしとして既定値6となる。 |
---|
151 | @param[in] field フィールド幅。 |
---|
152 | @param[in] flags 書式フラグ。 |
---|
153 | */ |
---|
154 | Sub FormatFloatE(sb As System.Text.StringBuilder, x As Double, precision As DWord, field As DWord, ByRef flags As FormatFlags) |
---|
155 | FormatFloatEx(sb, AddressOf(FormatFloatE_Convert), x, precision, field, flags) |
---|
156 | End Sub |
---|
157 | |
---|
158 | /*! |
---|
159 | @brief 浮動小数点数をprintfの%e, %E(指数形式、十進法)相当の変換で文字列化する関数。 |
---|
160 | @author Egtra |
---|
161 | @date 2008/03/07 |
---|
162 | @param[in,out] sb 書式化した文字列を追加するバッファ。 |
---|
163 | @param[in] x 文字列化する浮動小数点数値。 |
---|
164 | @param[in] precision 精度。小数点以下の桁数。DWORD_MAXのとき、指定なしとして15となる。 |
---|
165 | @param[in] field フィールド幅。 |
---|
166 | @param[in,out] flags 書式フラグ。 |
---|
167 | @todo 他の実装での末尾桁の扱いを調べる(このコードでは何もしていないので切捨となっている)。 |
---|
168 | */ |
---|
169 | Sub FormatFloatE_Convert(sb As System.Text.StringBuilder, x As Double, precision As DWord, field As DWord, ByRef flags As FormatFlags) |
---|
170 | If precision = DWORD_MAX Then |
---|
171 | precision = 15 |
---|
172 | End If |
---|
173 | Dim e As Long, negative As Boolean |
---|
174 | Dim s = FloatToChars(x, e, negative) |
---|
175 | FormatFloatE_Base(sb, s, negative, precision, flags) |
---|
176 | FormatFloatE_Exponent(sb, e, flags) |
---|
177 | End Sub |
---|
178 | |
---|
179 | /** |
---|
180 | @brief FormatFloatEの符号・基数部の出力用。 |
---|
181 | @author Egtra |
---|
182 | @date 2007/10/27 |
---|
183 | */ |
---|
184 | Sub FormatFloatE_Base(sb As System.Text.StringBuilder, s As String, negative As Boolean, precision As DWord, ByRef flags As FormatFlags) |
---|
185 | With sb |
---|
186 | AppendSign(sb, negative, flags) |
---|
187 | .Append(s[0]) |
---|
188 | If (flags And Alt) Or precision > 0 Then |
---|
189 | .Append(".") |
---|
190 | Dim outputLen = s.Length - 1 |
---|
191 | If outputLen >= precision Then |
---|
192 | .Append(s, 1, precision) |
---|
193 | Else 'sで用意された桁が指定された精度より少ないとき |
---|
194 | .Append(s, 1, outputLen) |
---|
195 | .Append(&h30 As Char, precision - outputLen) '足りない桁は0埋め |
---|
196 | End If |
---|
197 | End If |
---|
198 | End With |
---|
199 | End Sub |
---|
200 | |
---|
201 | /** |
---|
202 | @brief FormatFloatEの指数部の出力用。 |
---|
203 | @author Egtra |
---|
204 | @date 2007/10/27 |
---|
205 | */ |
---|
206 | Sub FormatFloatE_Exponent(sb As System.Text.StringBuilder, e As Long, flags As FormatFlags) |
---|
207 | With sb |
---|
208 | If flags And Cap Then |
---|
209 | .Append("E") |
---|
210 | Else |
---|
211 | .Append("e") |
---|
212 | End If |
---|
213 | FormatIntegerD(sb, e, 2, 0, Sign Or Zero) |
---|
214 | End With |
---|
215 | End Sub |
---|
216 | |
---|
217 | /*! |
---|
218 | @brief 浮動小数点数をprintfの%f(小数形式、十進法)相当の変換で文字列化する関数。 |
---|
219 | @author Egtra |
---|
220 | @date 2007/10/23 |
---|
221 | @param[in] x 文字列化する浮動小数点数値。 |
---|
222 | @param[in] precision 精度。小数点以下の桁数。DWORD_MAXのとき、指定なしとして既定値15となる。 |
---|
223 | @param[in] field フィールド幅。 |
---|
224 | @param[in] flags 書式フラグ。 |
---|
225 | @return xの文字列表現 |
---|
226 | */ |
---|
227 | Function FormatFloatF(x As Double, precision As DWord, field As DWord, flags As FormatFlags) As String |
---|
228 | FormatFloatF = FormatFloatEx(AddressOf(FormatFloatF_Convert), x, precision, field, flags) |
---|
229 | End Function |
---|
230 | |
---|
231 | /* |
---|
232 | @brief 浮動小数点数をprintfの%f(小数形式、十進法)相当の変換で文字列化する関数。 |
---|
233 | @author Egtra |
---|
234 | @date 2008/03/08 |
---|
235 | @param[in,out] sb 書式化した文字列を追加するバッファ。 |
---|
236 | @param[in] x 文字列化する浮動小数点数値。 |
---|
237 | @param[in] precision 精度。小数点以下の桁数。DWORD_MAXのとき、指定なしとして既定値6となる。 |
---|
238 | @param[in] field フィールド幅。 |
---|
239 | @param[in] flags 書式フラグ。 |
---|
240 | */ |
---|
241 | Sub FormatFloatF(sb As System.Text.StringBuilder, x As Double, precision As DWord, field As DWord, ByRef flags As FormatFlags) |
---|
242 | FormatFloatEx(sb, AddressOf(FormatFloatF_Convert), x, precision, field, flags) |
---|
243 | End Sub |
---|
244 | |
---|
245 | /*! |
---|
246 | @brief 浮動小数点数をprintfの%f(小数形式、十進法)相当の変換で文字列化する関数。 |
---|
247 | @author Egtra |
---|
248 | @date 2008/03/07 |
---|
249 | @param[in,out] sb 書式化した文字列を追加するバッファ。 |
---|
250 | @param[in] x 文字列化する浮動小数点数値。 |
---|
251 | @param[in] precision 精度。小数点以下の桁数。DWORD_MAXのとき、指定なしとして既定値15となる。 |
---|
252 | @param[in] field フィールド幅。 |
---|
253 | @param[in,out] flags 書式フラグ。 |
---|
254 | */ |
---|
255 | Sub FormatFloatF_Convert(sb As System.Text.StringBuilder, x As Double, precision As DWord, field As DWord, ByRef flags As FormatFlags) |
---|
256 | If precision = DWORD_MAX Then |
---|
257 | precision = 15 |
---|
258 | End If |
---|
259 | Dim e As Long, negative As Boolean |
---|
260 | Dim s = FloatToChars(x, e, negative) |
---|
261 | FormatFloatF_Core(sb, s, e, negative, precision, flags) |
---|
262 | End Sub |
---|
263 | |
---|
264 | /** |
---|
265 | @author Egtra |
---|
266 | @date 2007/10/27 |
---|
267 | */ |
---|
268 | Sub FormatFloatF_Core(sb As System.Text.StringBuilder, s As String, e As Long, negative As Boolean, precision As DWord, ByRef flags As FormatFlags) |
---|
269 | With sb |
---|
270 | AppendSign(sb, negative, flags) |
---|
271 | |
---|
272 | Dim intPartLen = e + 1 |
---|
273 | Dim outputDigit = 0 As DWord |
---|
274 | If intPartLen >= 17 Then |
---|
275 | '有効桁が全て整数部に収まる場合 |
---|
276 | .Append(s) |
---|
277 | .Append(&h30 As Char, intPartLen - 17) |
---|
278 | outputDigit = 17 |
---|
279 | ElseIf intPartLen > 0 Then |
---|
280 | '有効桁の一部が整数部にかかる場合 |
---|
281 | .Append(s, 0, intPartLen) |
---|
282 | outputDigit = intPartLen |
---|
283 | Else |
---|
284 | '有効桁が全く整数部にかからない場合 |
---|
285 | .Append(&h30 As Char) |
---|
286 | End If |
---|
287 | |
---|
288 | If precision > 0 Or (flags And Alt) Then |
---|
289 | .Append(".") |
---|
290 | |
---|
291 | Dim lastDigit = s.Length - outputDigit |
---|
292 | If lastDigit >= precision Then '変換して得られた文字列の桁数が精度以上ある場合 |
---|
293 | Dim zeroDigit = 0 |
---|
294 | If intPartLen < 0 Then |
---|
295 | '1.23e-4 = 0.000123のように指数が負のため小数点以下に0が続く場合 |
---|
296 | zeroDigit = System.Math.Min(-intPartLen As DWord, precision) |
---|
297 | .Append(&h30 As Char, zeroDigit As Long) |
---|
298 | End If |
---|
299 | .Append(s, outputDigit, (precision - zeroDigit) As Long) |
---|
300 | Else |
---|
301 | .Append(s, outputDigit, lastDigit) |
---|
302 | .Append(&h30 As Char, (precision - lastDigit) As Long) '残りの桁は0埋め |
---|
303 | End If |
---|
304 | End If |
---|
305 | End With |
---|
306 | End Sub |
---|
307 | |
---|
308 | /*! |
---|
309 | @brief 浮動小数点数をprintfの%g, %G(小数・指数、十進法)相当の変換で文字列化する関数。 |
---|
310 | @author Egtra |
---|
311 | @date 2007/10/23 |
---|
312 | @param[in] x 文字列化する浮動小数点数値。 |
---|
313 | @param[in] precision 精度。小数点以下の桁数。DWORD_MAXまたは0のとき、指定なしとして既定値15となる。 |
---|
314 | @param[in] field フィールド幅。 |
---|
315 | @param[in] flags 書式フラグ。 |
---|
316 | @return xの文字列表現 |
---|
317 | @todo 下位桁の扱いの調査。 |
---|
318 | */ |
---|
319 | Function FormatFloatG(x As Double, precision As DWord, field As DWord, flags As FormatFlags) As String |
---|
320 | FormatFloatG = FormatFloatEx(AddressOf(FormatFloatG_Convert), x, precision, field, flags) |
---|
321 | End Function |
---|
322 | |
---|
323 | /* |
---|
324 | @brief 浮動小数点数をprintfの%g, %G(小数・指数、十進法)相当の変換で文字列化する関数。 |
---|
325 | @author Egtra |
---|
326 | @date 2008/03/08 |
---|
327 | @param[in,out] sb 書式化した文字列を追加するバッファ。 |
---|
328 | @param[in] x 文字列化する浮動小数点数値。 |
---|
329 | @param[in] precision 精度。小数点以下の桁数。DWORD_MAXのとき、指定なしとして既定値6となる。 |
---|
330 | @param[in] field フィールド幅。 |
---|
331 | @param[in] flags 書式フラグ。 |
---|
332 | */ |
---|
333 | Sub FormatFloatG(sb As System.Text.StringBuilder, x As Double, precision As DWord, field As DWord, ByRef flags As FormatFlags) |
---|
334 | FormatFloatEx(sb, AddressOf(FormatFloatG_Convert), x, precision, field, flags) |
---|
335 | End Sub |
---|
336 | |
---|
337 | /*! |
---|
338 | @brief 浮動小数点数をprintfの%g, %G(小数・指数、十進法)相当の変換で文字列化する関数。 |
---|
339 | @author Egtra |
---|
340 | @date 2007/10/23 |
---|
341 | @param[in,out] sb 書式化した文字列を追加するバッファ。 |
---|
342 | @param[in] x 文字列化する浮動小数点数値。 |
---|
343 | @param[in] precision 精度。小数点以下の桁数。DWORD_MAXまたは0のとき、指定なしとして既定値15となる。 |
---|
344 | @param[in] field フィールド幅。 |
---|
345 | @param[in,out] flags 書式フラグ。 |
---|
346 | @todo 下位桁の扱いの調査。 |
---|
347 | */ |
---|
348 | Sub FormatFloatG_Convert(sb As System.Text.StringBuilder, x As Double, precision As DWord, field As DWord, ByRef flags As FormatFlags) |
---|
349 | 'GではE/Fと違い整数部も有効桁数に数えるのでその分を引いておく。 |
---|
350 | If precision = DWORD_MAX Or precision = 0 Then |
---|
351 | precision = 14 |
---|
352 | Else |
---|
353 | precision-- |
---|
354 | End If |
---|
355 | Dim lastLength = sb.Length |
---|
356 | Dim e As Long, negative As Boolean |
---|
357 | Dim s = FloatToChars(x, e, negative) |
---|
358 | If -5 < e And e < precision Then |
---|
359 | FormatFloatF_Core(sb, s, e, negative, -e + precision, flags) |
---|
360 | FormatFloatG_RemoveLowDigit(sb, lastLength, flags) |
---|
361 | Else |
---|
362 | FormatFloatE_Base(sb, s, negative, precision, flags) |
---|
363 | FormatFloatG_RemoveLowDigit(sb, lastLength, flags) |
---|
364 | FormatFloatE_Exponent(sb, e, flags) |
---|
365 | End If |
---|
366 | End Sub |
---|
367 | |
---|
368 | /*! |
---|
369 | @brief FormatFloatG/A用の小数点以下末尾の0を削除するルーチン |
---|
370 | @author Egtra |
---|
371 | @date 2007/10/27 |
---|
372 | @param[in, out] sb 文字列バッファ |
---|
373 | @param[in] flags フラグ |
---|
374 | flagsでAltが立っているとき、この関数は何もしない。 |
---|
375 | */ |
---|
376 | Sub FormatFloatG_RemoveLowDigit(sb As System.Text.StringBuilder, start As Long, flags As FormatFlags) |
---|
377 | Imports ActiveBasic.Strings |
---|
378 | |
---|
379 | Dim count = sb.Length |
---|
380 | If (flags And Alt) = 0 Then |
---|
381 | Dim p = StrPtr(sb) |
---|
382 | Dim point = ChrFind(VarPtr(p[start]), (count - start) As SIZE_T, Asc(".")) |
---|
383 | If point = -1 Then |
---|
384 | Debug |
---|
385 | End If |
---|
386 | |
---|
387 | Dim i As Long |
---|
388 | For i = count - 1 To point + 1 Step -1 |
---|
389 | If sb[i] <> &h30 Then |
---|
390 | Exit For |
---|
391 | End If |
---|
392 | Next |
---|
393 | If i <> point Then |
---|
394 | i++ |
---|
395 | End If |
---|
396 | sb.Length = i |
---|
397 | End If |
---|
398 | End Sub |
---|
399 | |
---|
400 | /*! |
---|
401 | @brief 浮動小数点数をprintfの%a, %A(指数形式、十六進法)相当の変換で文字列化する関数。 |
---|
402 | @author Egtra |
---|
403 | @date 2007/09/18 |
---|
404 | @param[in] x 文字列化する浮動小数点数値。 |
---|
405 | @param[in] precision 精度。小数点以下の桁数。DWORD_MAXのとき、指定なしとして既定値13となる。 |
---|
406 | @param[in] field フィールド幅。 |
---|
407 | @param[in] flags 書式フラグ。 |
---|
408 | @return xの文字列表現 |
---|
409 | |
---|
410 | C99では、末尾の0を取り除いても良いとあるので、 |
---|
411 | このルーチンでは取り除くことにしている。 |
---|
412 | */ |
---|
413 | Function FormatFloatA(x As Double, precision As DWord, field As DWord, flags As FormatFlags) As String |
---|
414 | FormatFloatA = FormatFloatEx(AddressOf(FormatFloatA_Convert), x, precision, field, flags) |
---|
415 | End Function |
---|
416 | |
---|
417 | /* |
---|
418 | @brief 浮動小数点数をprintfの%a, %A(指数形式、十六進法)相当の変換で文字列化する関数。 |
---|
419 | @author Egtra |
---|
420 | @date 2008/03/08 |
---|
421 | @param[in,out] sb 書式化した文字列を追加するバッファ。 |
---|
422 | @param[in] x 文字列化する浮動小数点数値。 |
---|
423 | @param[in] precision 精度。小数点以下の桁数。DWORD_MAXのとき、指定なしとして既定値6となる。 |
---|
424 | @param[in] field フィールド幅。 |
---|
425 | @param[in] flags 書式フラグ。 |
---|
426 | */ |
---|
427 | Sub FormatFloatA(sb As System.Text.StringBuilder, x As Double, precision As DWord, field As DWord, ByRef flags As FormatFlags) |
---|
428 | FormatFloatEx(sb, AddressOf(FormatFloatA_Convert), x, precision, field, flags) |
---|
429 | End Sub |
---|
430 | |
---|
431 | /*! |
---|
432 | @brief 浮動小数点数をprintfの%a, %A(指数形式、十六進法)相当の変換で文字列化する関数。 |
---|
433 | @author Egtra |
---|
434 | @date 2008/03/07 |
---|
435 | @param[in,out] sb 書式化した文字列を追加するバッファ。 |
---|
436 | @param[in] x 文字列化する浮動小数点数値。 |
---|
437 | @param[in] precision 精度。小数点以下の桁数。DWORD_MAXのとき、指定なしとして既定値13となる。 |
---|
438 | @param[in] field フィールド幅。 |
---|
439 | @param[in,out] flags 書式フラグ。 |
---|
440 | |
---|
441 | C99では、末尾の0を取り除いても良いとあるので、 |
---|
442 | このルーチンでは取り除くことにしている。 |
---|
443 | */ |
---|
444 | Sub FormatFloatA_Convert(sb As System.Text.StringBuilder, x As Double, precision As DWord, field As DWord, ByRef flags As FormatFlags) |
---|
445 | If precision = DWORD_MAX Then |
---|
446 | precision = 13 |
---|
447 | End If |
---|
448 | Dim lastLength = sb.Length |
---|
449 | Dim pqw = VarPtr(x) As *QWord |
---|
450 | |
---|
451 | With sb |
---|
452 | Dim sign = (GetQWord(pqw) And &H8000000000000000) As Boolean |
---|
453 | pqw[0] And= &h7fffffffffffffff |
---|
454 | |
---|
455 | AppendSign(sb, sign, flags) |
---|
456 | |
---|
457 | If flags And BPrefix Then |
---|
458 | .Append("&H") |
---|
459 | Else |
---|
460 | .Append("0X") |
---|
461 | End If |
---|
462 | |
---|
463 | Dim biasedExp = (GetQWord(pqw) >> 52) As DWord And &h7FF |
---|
464 | Dim exp As Long |
---|
465 | If biasedExp = 0 Then |
---|
466 | If GetQWord(pqw) <> 0 Then |
---|
467 | exp = -1022 '非正規化数への対応 |
---|
468 | Else |
---|
469 | exp = 0 |
---|
470 | End If |
---|
471 | .Append("0") |
---|
472 | Else |
---|
473 | exp = biasedExp - 1023 |
---|
474 | .Append("1") |
---|
475 | End If |
---|
476 | |
---|
477 | If precision > 0 Or (flags And Alt) Then |
---|
478 | .Append(".") |
---|
479 | Dim fraction = GetQWord(pqw) And &h000fffffffffffff |
---|
480 | If precision < 13 Then |
---|
481 | Dim dropped = 13 - precision |
---|
482 | fraction >>= dropped * 4 |
---|
483 | FormatIntegerLX(sb, fraction, precision, 0, flags And Cap) |
---|
484 | Else |
---|
485 | FormatIntegerLX(sb, fraction, 13, 0, flags And Cap) |
---|
486 | .Append(&h30, precision - 13) |
---|
487 | End If |
---|
488 | End If |
---|
489 | FormatFloatG_RemoveLowDigit(sb, lastLength, flags) |
---|
490 | .Append("P") |
---|
491 | FormatIntegerD(sb, exp, 1, 0, Sign) |
---|
492 | AdjustAlphabet(sb, flags, lastLength) |
---|
493 | End With |
---|
494 | End Sub |
---|
495 | |
---|
496 | /*! |
---|
497 | @brief 先頭に符号もしくはその分の空白を出力する。FormatFloat用。 |
---|
498 | @author Egtra |
---|
499 | @date 2007/10/23 |
---|
500 | @param[in, out] sb 出力先 |
---|
501 | @param[in] negative 符号 |
---|
502 | @param[in, out] flags フラグ。negative = Trueなら、Signを立てて返す。 |
---|
503 | */ |
---|
504 | Sub AppendSign(sb As System.Text.StringBuilder, negative As Boolean, ByRef flags As FormatFlags) |
---|
505 | With sb |
---|
506 | If negative Then |
---|
507 | .Append("-") |
---|
508 | flags Or= Sign |
---|
509 | Else |
---|
510 | If flags And Sign Then |
---|
511 | .Append("+") |
---|
512 | ElseIf flags And Blank Then |
---|
513 | .Append(" ") |
---|
514 | End If |
---|
515 | End If |
---|
516 | End With |
---|
517 | End Sub |
---|
518 | |
---|
519 | /*! |
---|
520 | @brief 符号無し整数をprintfの%u(十進法表現)相当の変換で文字列化する関数。 |
---|
521 | @author Egtra |
---|
522 | @date 2007/09/18 |
---|
523 | @param[in] x 文字列化する整数値。 |
---|
524 | @param[in] d 精度、最小限表示される桁数。DWORD_MAXのとき、指定なしとして、既定値1となる。 |
---|
525 | @param[in] field フィールド幅。 |
---|
526 | @param[in] flags 書式フラグ。 |
---|
527 | @return xの文字列表現 |
---|
528 | */ |
---|
529 | Function FormatIntegerU(x As DWord, d As DWord, field As DWord, flags As FormatFlags) As String |
---|
530 | Return FormatIntegerEx(TraitsIntegerU[0], x, d, field, flags And (Not (Sign Or Blank))) |
---|
531 | End Function |
---|
532 | |
---|
533 | /*! |
---|
534 | @brief 符号無し整数をprintfの%u(十進法表現)相当の変換で文字列化する関数。 |
---|
535 | @author Egtra |
---|
536 | @date 2008/03/07 |
---|
537 | @param[in,out] sb 書式化した文字列を追加するバッファ。 |
---|
538 | @param[in] x 文字列化する整数値。 |
---|
539 | @param[in] d 精度、最小限表示される桁数。DWORD_MAXのとき、指定なしとして、既定値1となる。 |
---|
540 | @param[in] field フィールド幅。 |
---|
541 | @param[in] flags 書式フラグ。 |
---|
542 | */ |
---|
543 | Sub FormatIntegerU(sb As System.Text.StringBuilder, x As DWord, d As DWord, field As DWord, flags As FormatFlags) |
---|
544 | FormatIntegerEx(sb, TraitsIntegerU[0], x As QWord, d, field, flags And (Not (Sign Or Blank))) |
---|
545 | End Sub |
---|
546 | |
---|
547 | /*! |
---|
548 | @brief FormatIntegerUのQWord版 |
---|
549 | @author Egtra |
---|
550 | @date 2007/10/26 |
---|
551 | */ |
---|
552 | Function FormatIntegerLU(x As QWord, d As DWord, field As DWord, flags As FormatFlags) As String |
---|
553 | Return FormatIntegerEx(TraitsIntegerU[1], x, d, field, flags And (Not (Sign Or Blank))) |
---|
554 | End Function |
---|
555 | |
---|
556 | /*! |
---|
557 | @brief FormatIntegerUのQWord版 |
---|
558 | @author Egtra |
---|
559 | @date 2008/03/07 |
---|
560 | @param[in,out] sb 書式化した文字列を追加するバッファ。 |
---|
561 | @param[in] x 文字列化する整数値。 |
---|
562 | @param[in] d 精度、最小限表示される桁数。DWORD_MAXのとき、指定なしとして、既定値1となる。 |
---|
563 | @param[in] field フィールド幅。 |
---|
564 | @param[in] flags 書式フラグ。 |
---|
565 | */ |
---|
566 | Sub FormatIntegerLU(sb As System.Text.StringBuilder, x As QWord, d As DWord, field As DWord, flags As FormatFlags) |
---|
567 | FormatIntegerEx(sb, TraitsIntegerU[0], x, d, field, flags And (Not (Sign Or Blank))) |
---|
568 | End Sub |
---|
569 | |
---|
570 | /*! |
---|
571 | @brief 符号有り整数をprintfの%d(十進法表現)相当の変換で文字列化する関数。 |
---|
572 | @author Egtra |
---|
573 | @date 2007/10/13 |
---|
574 | @param[in] x 文字列化する整数値。 |
---|
575 | @param[in] d 精度、最小限表示される桁数。DWORD_MAXのとき、指定なしとして、既定値1となる。 |
---|
576 | @param[in] field フィールド幅。 |
---|
577 | @param[in] flags 書式フラグ。 |
---|
578 | @return xの文字列表現 |
---|
579 | */ |
---|
580 | Function FormatIntegerD(x As Long, d As DWord, field As DWord, flags As FormatFlags) As String |
---|
581 | Return FormatIntegerEx(TraitsIntegerD[0], (x As Int64) As QWord, d, field, flags) |
---|
582 | End Function |
---|
583 | |
---|
584 | /*! |
---|
585 | @brief 符号有り整数をprintfの%d(十進法表現)相当の変換で文字列化する関数。 |
---|
586 | @author Egtra |
---|
587 | @date 2008/03/07 |
---|
588 | @param[in,out] sb 書式化した文字列を追加するバッファ。 |
---|
589 | @param[in] x 文字列化する整数値。 |
---|
590 | @param[in] d 精度、最小限表示される桁数。DWORD_MAXのとき、指定なしとして、既定値1となる。 |
---|
591 | @param[in] field フィールド幅。 |
---|
592 | @param[in] flags 書式フラグ。 |
---|
593 | */ |
---|
594 | Sub FormatIntegerD(sb As System.Text.StringBuilder, x As Long, d As DWord, field As DWord, flags As FormatFlags) |
---|
595 | FormatIntegerEx(sb, TraitsIntegerD[0], (x As Int64) As QWord, d, field, flags) |
---|
596 | End Sub |
---|
597 | |
---|
598 | /*! |
---|
599 | @brief FormatIntegerDのInt64版 |
---|
600 | @author Egtra |
---|
601 | @date 2007/10/26 |
---|
602 | */ |
---|
603 | Function FormatIntegerLD(x As Int64, d As DWord, field As DWord, flags As FormatFlags) As String |
---|
604 | Return FormatIntegerEx(TraitsIntegerD[1], x As QWord, d, field, flags) |
---|
605 | End Function |
---|
606 | |
---|
607 | /*! |
---|
608 | @brief FormatIntegerDのInt64版 |
---|
609 | @author Egtra |
---|
610 | @date 2007/10/26 |
---|
611 | */ |
---|
612 | Sub FormatIntegerLD(sb As System.Text.StringBuilder, x As Int64, d As DWord, field As DWord, flags As FormatFlags) |
---|
613 | FormatIntegerEx(sb, TraitsIntegerD[1], x As QWord, d, field, flags) |
---|
614 | End Sub |
---|
615 | |
---|
616 | /*! |
---|
617 | @author Egtra |
---|
618 | @date 2007/10/26 |
---|
619 | */ |
---|
620 | Dim TraitsIntegerU[1] As IntegerConvertTraits |
---|
621 | With TraitsIntegerU[0] |
---|
622 | .Convert = AddressOf(IntegerU_Convert) |
---|
623 | .Prefix = AddressOf(IntegerU_Prefix) |
---|
624 | End With |
---|
625 | |
---|
626 | With TraitsIntegerU[1] |
---|
627 | .Convert = AddressOf(IntegerLU_Convert) |
---|
628 | .Prefix = AddressOf(IntegerU_Prefix) |
---|
629 | End With |
---|
630 | |
---|
631 | /*! |
---|
632 | @author Egtra |
---|
633 | @date 2007/10/28 |
---|
634 | */ |
---|
635 | Dim TraitsIntegerD[1] As IntegerConvertTraits |
---|
636 | With TraitsIntegerD[0] |
---|
637 | .Convert = AddressOf(IntegerD_Convert) |
---|
638 | .Prefix = AddressOf(IntegerD_Prefix) |
---|
639 | End With |
---|
640 | |
---|
641 | With TraitsIntegerD[1] |
---|
642 | .Convert = AddressOf(IntegerLD_Convert) |
---|
643 | .Prefix = AddressOf(IntegerD_Prefix) |
---|
644 | End With |
---|
645 | |
---|
646 | /*! |
---|
647 | @brief 負数を表すフラグ。FormatIntegerD, LDからIntegerDU_Prefixまでの内部処理用。 |
---|
648 | @author Egtra |
---|
649 | @date 2007/10/26 |
---|
650 | */ |
---|
651 | Const Minus = Reserved |
---|
652 | |
---|
653 | /*! |
---|
654 | @author Egtra |
---|
655 | @date 2007/10/26 |
---|
656 | */ |
---|
657 | Function IntegerU_Convert(buf As *Char, xq As QWord, flags As FormatFlags) As DWord |
---|
658 | Dim x = xq As DWord |
---|
659 | Dim i = MaxSizeLO |
---|
660 | While x <> 0 |
---|
661 | buf[i] = (x As Int64 Mod 10 + &h30) As Char 'Int64への型変換は#117対策 |
---|
662 | x \= 10 |
---|
663 | i-- |
---|
664 | Wend |
---|
665 | Return i |
---|
666 | End Function |
---|
667 | |
---|
668 | /*! |
---|
669 | @brief IntegerU_ConvertのQWord版 |
---|
670 | @author Egtra |
---|
671 | @date 2007/10/26 |
---|
672 | @bug #117のため、現在Int64の最大値を超える値を正しく処理できない。 |
---|
673 | */ |
---|
674 | Function IntegerLU_Convert(buf As *Char, x As QWord, flags As FormatFlags) As DWord |
---|
675 | Dim i = MaxSizeLO |
---|
676 | While x <> 0 |
---|
677 | buf[i] = (x As Int64 Mod 10 + &h30) As Char 'Int64への型変換は#117対策 |
---|
678 | x \= 10 |
---|
679 | i-- |
---|
680 | Wend |
---|
681 | Return i |
---|
682 | End Function |
---|
683 | |
---|
684 | /*! |
---|
685 | @author Egtra |
---|
686 | @date 2007/10/26 |
---|
687 | */ |
---|
688 | Function IntegerU_Prefix(x As QWord, flags As FormatFlags) As String |
---|
689 | End Function |
---|
690 | |
---|
691 | /*! |
---|
692 | @author Egtra |
---|
693 | @date 2007/10/28 |
---|
694 | */ |
---|
695 | Function IntegerD_Convert(buf As *Char, xq As QWord, flags As FormatFlags) As DWord |
---|
696 | Return IntegerU_Convert(buf, Abs((xq As DWord) As Long) As DWord, flags) |
---|
697 | End Function |
---|
698 | |
---|
699 | /*! |
---|
700 | @brief IntegerD_ConvertのInt64版 |
---|
701 | @author Egtra |
---|
702 | @date 2007/10/28 |
---|
703 | */ |
---|
704 | Function IntegerLD_Convert(buf As *Char, x As QWord, flags As FormatFlags) As DWord |
---|
705 | Return IntegerLU_Convert(buf, Abs(x As Int64) As QWord, flags) |
---|
706 | End Function |
---|
707 | |
---|
708 | /*! |
---|
709 | @author Egtra |
---|
710 | @date 2007/10/28 |
---|
711 | */ |
---|
712 | Function IntegerD_Prefix(x As QWord, flags As FormatFlags) As String |
---|
713 | If (x As Int64) < 0 Then |
---|
714 | IntegerD_Prefix = "-" |
---|
715 | ElseIf flags And Sign Then |
---|
716 | IntegerD_Prefix = "+" |
---|
717 | ElseIf flags And Blank Then |
---|
718 | IntegerD_Prefix = " " |
---|
719 | End If |
---|
720 | End Function |
---|
721 | |
---|
722 | |
---|
723 | |
---|
724 | /*! |
---|
725 | @brief QWordの最大値の八進法表現1777777777777777777777の文字数 - 1 + 1。IntegerO_Convert内で使用。 |
---|
726 | @author Egtra |
---|
727 | @date 2007/10/26 |
---|
728 | 上の式で1を加えているのは、八進接頭辞の分。 |
---|
729 | */ |
---|
730 | Const MaxSizeLO = 22 |
---|
731 | |
---|
732 | /*! |
---|
733 | @author Egtra |
---|
734 | @date 2007/10/22 |
---|
735 | */ |
---|
736 | Dim TraitsIntegerO[1] As IntegerConvertTraits |
---|
737 | With TraitsIntegerO[0] |
---|
738 | .Convert = AddressOf(IntegerO_Convert) |
---|
739 | .Prefix = AddressOf(IntegerO_Prefix) |
---|
740 | End With |
---|
741 | |
---|
742 | With TraitsIntegerO[1] |
---|
743 | .Convert = AddressOf(IntegerLO_Convert) |
---|
744 | .Prefix = AddressOf(IntegerO_Prefix) |
---|
745 | End With |
---|
746 | |
---|
747 | /*! |
---|
748 | @brief 符号無し整数をprintfの%o(八進法表現)相当の変換で文字列化する関数。 |
---|
749 | @author Egtra |
---|
750 | @date 2007/10/19 |
---|
751 | @param[in] x 文字列化する整数値。 |
---|
752 | @param[in] d 精度、最小限表示される桁数。DWORD_MAXのとき、指定なしとして、既定値1となる。 |
---|
753 | @param[in] field フィールド幅。 |
---|
754 | @param[in] flags 書式フラグ。 |
---|
755 | @return xの文字列表現 |
---|
756 | */ |
---|
757 | Function FormatIntegerO(x As DWord, d As DWord, field As DWord, flags As FormatFlags) As String |
---|
758 | Return FormatIntegerEx(TraitsIntegerO[0], x, d, field, flags) |
---|
759 | End Function |
---|
760 | |
---|
761 | /*! |
---|
762 | @brief FormatIntegerOのQWord版。 |
---|
763 | @author Egtra |
---|
764 | @date 2007/10/26 |
---|
765 | */ |
---|
766 | Function FormatIntegerLO(x As QWord, d As DWord, field As DWord, flags As FormatFlags) As String |
---|
767 | Return FormatIntegerEx(TraitsIntegerO[1], x, d, field, flags) |
---|
768 | End Function |
---|
769 | |
---|
770 | /*! |
---|
771 | @author Egtra |
---|
772 | @date 2007/10/22 |
---|
773 | */ |
---|
774 | Function IntegerO_Convert(buf As *Char, xq As QWord, flags As FormatFlags) As DWord |
---|
775 | Dim x = xq As DWord |
---|
776 | Dim i = MaxSizeLO |
---|
777 | While x <> 0 |
---|
778 | buf[i] = ((x And &o7) + &h30) As Char |
---|
779 | x >>= 3 |
---|
780 | i-- |
---|
781 | Wend |
---|
782 | If flags And Alt Then |
---|
783 | buf[i] = &h30 |
---|
784 | i-- |
---|
785 | End If |
---|
786 | Return i |
---|
787 | End Function |
---|
788 | |
---|
789 | /*! |
---|
790 | @brief IntegerO_ConvertのQWord版。 |
---|
791 | @author Egtra |
---|
792 | @date 2007/10/26 |
---|
793 | */ |
---|
794 | Function IntegerLO_Convert(buf As *Char, x As QWord, flags As FormatFlags) As DWord |
---|
795 | Dim i = MaxSizeLO |
---|
796 | While x <> 0 |
---|
797 | buf[i] = ((x And &o7) + &h30) As Char |
---|
798 | x >>= 3 |
---|
799 | i-- |
---|
800 | Wend |
---|
801 | If flags And Alt Then |
---|
802 | buf[i] = &h30 |
---|
803 | i-- |
---|
804 | End If |
---|
805 | Return i |
---|
806 | End Function |
---|
807 | |
---|
808 | /*! |
---|
809 | @author Egtra |
---|
810 | @date 2007/10/22 |
---|
811 | @note #フラグ (Alt)の処理は、IntegerO/LO_Convert内で行うので、ここで処理することはない。 |
---|
812 | */ |
---|
813 | Function IntegerO_Prefix(x As QWord, flags As FormatFlags) As String |
---|
814 | If flags And BPrefix Then |
---|
815 | If x <> 0 Then |
---|
816 | IntegerO_Prefix = "&O" |
---|
817 | End If |
---|
818 | End If |
---|
819 | End Function |
---|
820 | |
---|
821 | /*! |
---|
822 | @author Egtra |
---|
823 | @date 2007/10/24 |
---|
824 | */ |
---|
825 | Dim TraitsIntegerX[1] As IntegerConvertTraits |
---|
826 | With TraitsIntegerX[0] |
---|
827 | .Convert = AddressOf(IntegerX_Convert) |
---|
828 | .Prefix = AddressOf(IntegerX_Prefix) |
---|
829 | End With |
---|
830 | |
---|
831 | With TraitsIntegerX[1] |
---|
832 | .Convert = AddressOf(IntegerLX_Convert) |
---|
833 | .Prefix = AddressOf(IntegerX_Prefix) |
---|
834 | End With |
---|
835 | |
---|
836 | /*! |
---|
837 | @brief 整数をprintfの%x, %X(十六進法)相当の変換で文字列化する関数。 |
---|
838 | @author Egtra |
---|
839 | @date 2007/10/19 |
---|
840 | @param[in] x 文字列化する整数値。 |
---|
841 | @param[in] d 精度、最小限表示される桁数。DWORD_MAXのとき、指定なしとして、既定値1となる。 |
---|
842 | @param[in] field フィールド幅。 |
---|
843 | @param[in] flags 書式フラグ。 |
---|
844 | @return xの文字列表現 |
---|
845 | */ |
---|
846 | Function FormatIntegerX(x As DWord, d As DWord, field As DWord, flags As FormatFlags) As String |
---|
847 | Return FormatIntegerEx(TraitsIntegerX[0], x, d, field, flags) |
---|
848 | End Function |
---|
849 | |
---|
850 | /*! |
---|
851 | @brief FormatIntegerXのQWord版。 |
---|
852 | @author Egtra |
---|
853 | @date 2007/10/22 |
---|
854 | */ |
---|
855 | Function FormatIntegerLX(x As QWord, d As DWord, field As DWord, flags As FormatFlags) As String |
---|
856 | Return FormatIntegerEx(TraitsIntegerX[1], x, d, field, flags) |
---|
857 | End Function |
---|
858 | |
---|
859 | /*! |
---|
860 | @brief FormatIntegerXのQWord, StringBuilder版。 |
---|
861 | @author Egtra |
---|
862 | @date 2008/03/07 |
---|
863 | */ |
---|
864 | Sub FormatIntegerLX(sb As System.Text.StringBuilder, x As QWord, d As DWord, field As DWord, flags As FormatFlags) |
---|
865 | FormatIntegerEx(sb, TraitsIntegerX[1], x, d, field, flags) |
---|
866 | End Sub |
---|
867 | |
---|
868 | /* |
---|
869 | @brief 0からFまでの文字を収めた表 |
---|
870 | @author egtra |
---|
871 | */ |
---|
872 | Dim HexadecimalTable[&h10] = [&h30, &h31, &h32, &h33, &h34, &h35, &h36, &h37, &h38, &h39, &h41, &h42, &h43, &h44, &h45, &h46] As Byte |
---|
873 | |
---|
874 | /*! |
---|
875 | @author Egtra |
---|
876 | @date 2007/10/22 |
---|
877 | */ |
---|
878 | Function IntegerX_Convert(buf As *Char, xq As QWord, flags As FormatFlags) As DWord |
---|
879 | Dim i = MaxSizeLO |
---|
880 | Dim x = xq As DWord |
---|
881 | While x <> 0 |
---|
882 | buf[i] = HexadecimalTable[x And &h0f] |
---|
883 | x >>= 4 |
---|
884 | i-- |
---|
885 | Wend |
---|
886 | Return i |
---|
887 | End Function |
---|
888 | |
---|
889 | /*! |
---|
890 | @brief IntegerX_ConvertのQWord版。 |
---|
891 | @author Egtra |
---|
892 | @date 2007/10/22 |
---|
893 | */ |
---|
894 | Function IntegerLX_Convert(buf As *Char, x As QWord, flags As FormatFlags) As DWord |
---|
895 | Dim i = MaxSizeLO |
---|
896 | While x <> 0 |
---|
897 | buf[i] = HexadecimalTable[x And &h0f] |
---|
898 | x >>= 4 |
---|
899 | i-- |
---|
900 | Wend |
---|
901 | Return i |
---|
902 | End Function |
---|
903 | |
---|
904 | /*! |
---|
905 | @author Egtra |
---|
906 | @date 2007/10/24 |
---|
907 | */ |
---|
908 | Function IntegerX_Prefix(x As QWord, flags As FormatFlags) As String |
---|
909 | If x <> 0 Then |
---|
910 | If flags And Alt Then |
---|
911 | IntegerX_Prefix = "0X" |
---|
912 | ElseIf flags And BPrefix Then |
---|
913 | IntegerX_Prefix = "&H" |
---|
914 | End If |
---|
915 | End If |
---|
916 | End Function |
---|
917 | |
---|
918 | /*! |
---|
919 | @brief FormatIntegerExへ渡す変換特性を表す構造体型。 |
---|
920 | @author Egtra |
---|
921 | @date 2007/10/22 |
---|
922 | |
---|
923 | FormatIntegerの都合上、このファイル内で宣言しているIntegerConvertTraits型の |
---|
924 | 変数は全て配列となっている;[0]が32ビット変換、[1]が64ビット変換である。 |
---|
925 | */ |
---|
926 | Type IntegerConvertTraits |
---|
927 | '!変換を行う関数へのポインタ。 |
---|
928 | Convert As *Function(buf As *Char, x As QWord, flags As FormatFlags) As DWord |
---|
929 | '!接頭辞を取得する関数へのポインタ。 |
---|
930 | Prefix As *Function(x As QWord, flags As FormatFlags) As String |
---|
931 | End Type |
---|
932 | |
---|
933 | /*! |
---|
934 | @brief 整数変換全てを行う関数。 |
---|
935 | @author Egtra |
---|
936 | @date 2007/10/22 |
---|
937 | @param[in] tr 特性情報。 |
---|
938 | @param[in] x 変換元の数値。 |
---|
939 | @param[in] d 精度。ここでは最低限出力する桁数。 |
---|
940 | @param[in] field フィールド幅。 |
---|
941 | @param[in] flags フラグ。 |
---|
942 | @return 変換された文字列 |
---|
943 | */ |
---|
944 | Function FormatIntegerEx(ByRef tr As IntegerConvertTraits, x As QWord, d As DWord, field As DWord, flags As FormatFlags) As String |
---|
945 | Dim sb = New System.Text.StringBuilder(32) |
---|
946 | FormatIntegerEx(sb, tr, x, d, field, flags) |
---|
947 | FormatIntegerEx = sb.ToString |
---|
948 | End Function |
---|
949 | |
---|
950 | /*! |
---|
951 | @brief 整数変換全てを行う関数。これを雛形とし、形式毎の差異はIntegerConvertTraitsで表現する。 |
---|
952 | @author Egtra |
---|
953 | @date 2008/03/06 |
---|
954 | @param[in,out] sb 書式化した文字列を追加するバッファ。 |
---|
955 | @param[in] tr 特性情報。 |
---|
956 | @param[in] x 変換元の数値。 |
---|
957 | @param[in] d 精度。ここでは最低限出力する桁数。 |
---|
958 | @param[in] field フィールド幅。 |
---|
959 | @param[in] flags フラグ。 |
---|
960 | */ |
---|
961 | Sub FormatIntegerEx(sb As System.Text.StringBuilder, ByRef tr As IntegerConvertTraits, x As QWord, d As DWord, field As DWord, flags As FormatFlags) |
---|
962 | If d = DWORD_MAX Then |
---|
963 | d = 1 |
---|
964 | Else |
---|
965 | '精度が指定されているとき、ゼロフラグは無視される。 |
---|
966 | '仕様上、左揃えのときも無視されるが、それはAdjustFieldWidthが行ってくれる。 |
---|
967 | flags And= Not Zero |
---|
968 | End If |
---|
969 | |
---|
970 | Dim lastLength = sb.Length |
---|
971 | |
---|
972 | With sb |
---|
973 | Dim prefixFunc = tr.Prefix |
---|
974 | Dim prefix = prefixFunc(x, flags) |
---|
975 | sb.Append(prefix) |
---|
976 | |
---|
977 | Dim prefixLen = 0 As DWord |
---|
978 | If String.IsNullOrEmpty(prefix) = False Then |
---|
979 | prefixLen = prefix.Length As DWord |
---|
980 | End If |
---|
981 | |
---|
982 | 'バッファの量は最も必要文字数の多くなるUInt64の8進法変換にあわせている |
---|
983 | Dim buf[MaxSizeLO] As Char |
---|
984 | Dim convertFunc = tr.Convert |
---|
985 | Dim bufStartPos = convertFunc(buf, x, flags) |
---|
986 | |
---|
987 | Dim len = (MaxSizeLO - bufStartPos) As Long |
---|
988 | If len < 0 Then |
---|
989 | Debug |
---|
990 | End If |
---|
991 | If len < d Then |
---|
992 | .Append(&h30 As Char, d - len) |
---|
993 | End If |
---|
994 | .Append(buf, bufStartPos + 1, len) |
---|
995 | AdjustFieldWidth(sb, field, flags And (Not (Sign Or Blank)), prefixLen, lastLength) |
---|
996 | AdjustAlphabet(sb, flags, lastLength) |
---|
997 | End With |
---|
998 | End Sub |
---|
999 | |
---|
1000 | /*! |
---|
1001 | @brief 浮動小数点数変換全てを行う関数。これを雛形とし、実際の変換関数は引数converterで与える。 |
---|
1002 | @author Egtra |
---|
1003 | @date 2008/03/07 |
---|
1004 | @param[in,out] sb 書式化した文字列を追加するバッファ。 |
---|
1005 | @param[in] converter 変換関数。 |
---|
1006 | @param[in] x 変換元の数値。 |
---|
1007 | @param[in] d 精度。ここでは最低限出力する桁数。 |
---|
1008 | @param[in] field フィールド幅。 |
---|
1009 | @param[in] flags フラグ。 |
---|
1010 | */ |
---|
1011 | Sub FormatFloatEx(sb As System.Text.StringBuilder, converter As FormatFloatProc, x As Double, precision As DWord, field As DWord, flags As FormatFlags) |
---|
1012 | Dim lastLength = sb.Length |
---|
1013 | If Math.IsNaN(x) Then |
---|
1014 | sb.Append("NAN") |
---|
1015 | AdjustAlphabet(sb, flags, lastLength) |
---|
1016 | ElseIf Math.IsInf(x) Then |
---|
1017 | AppendSign(sb, (GetQWord(VarPtr(x)) >> 63) As Boolean, flags) |
---|
1018 | sb.Append("INFINITY") |
---|
1019 | AdjustAlphabet(sb, flags, lastLength) |
---|
1020 | Else |
---|
1021 | converter(sb, x, precision, field, flags) |
---|
1022 | End If |
---|
1023 | AdjustFieldWidth(sb, field, flags, 0, lastLength) |
---|
1024 | End Sub |
---|
1025 | |
---|
1026 | |
---|
1027 | /*! |
---|
1028 | @brief 浮動小数点数変換全てを行う関数。 |
---|
1029 | @author Egtra |
---|
1030 | @date 2008/03/08 |
---|
1031 | @param[in] converter 変換関数。 |
---|
1032 | @param[in] x 変換元の数値。 |
---|
1033 | @param[in] d 精度。ここでは最低限出力する桁数。 |
---|
1034 | @param[in] field フィールド幅。 |
---|
1035 | @param[in] flags フラグ。 |
---|
1036 | @return 変換された文字列。 |
---|
1037 | */ |
---|
1038 | Function FormatFloatEx(converter As FormatFloatProc, x As Double, precision As DWord, field As DWord, flags As FormatFlags) As String |
---|
1039 | Dim sb = New System.Text.StringBuilder |
---|
1040 | FormatFloatEx(sb, converter, x, precision, field, flags) |
---|
1041 | FormatFloatEx = sb.ToString |
---|
1042 | End Function |
---|
1043 | |
---|
1044 | /*! |
---|
1045 | @brief 書式化の仕上げとして、Capフラグが指定されていないときに小文字化する作業を行う。 |
---|
1046 | @author Egtra |
---|
1047 | @date 2008/03/06 |
---|
1048 | @param[in,out] sb 書式化した文字列を格納しているバッファ。 |
---|
1049 | @param[in] flags フラグ。 |
---|
1050 | @param[in] offset 書式変換した部分の開始位置。 |
---|
1051 | */ |
---|
1052 | Sub AdjustAlphabet(sb As System.Text.StringBuilder, flags As FormatFlags, offset As Long) |
---|
1053 | If (flags And Cap) = 0 Then |
---|
1054 | Dim len = sb.Length |
---|
1055 | Dim i As Long |
---|
1056 | For i = offset To ELM(len) |
---|
1057 | sb[i] = CType.ToLower(sb[i]) |
---|
1058 | Next |
---|
1059 | End If |
---|
1060 | End Sub |
---|
1061 | |
---|
1062 | /*! |
---|
1063 | @brief 書式化の仕上げとして、変換部分がフィールド幅まで満たされるように空白などを挿入する。 |
---|
1064 | @author Egtra |
---|
1065 | @date 2007/10/13 |
---|
1066 | @param[in,out] sb 対象文字列 |
---|
1067 | @param[in] field フィールド幅 |
---|
1068 | @param[in] hasSign 符号を持っている(負の値か)か否か |
---|
1069 | @param[in] flags フラグ |
---|
1070 | @param[in] prefixLen (あれば)接頭辞の文字数。ゼロ埋めする際、この数だけ挿入位置を後ろにする。 |
---|
1071 | @param[in] offset 変換した部分へのオフセット。AppendではなくInsertを行う際に用いられる。 |
---|
1072 | sbが"-1"のように負符号を持っている場合は、呼出元でSignフラグ(またはBlank)を立てること。 |
---|
1073 | */ |
---|
1074 | Sub AdjustFieldWidth(sb As System.Text.StringBuilder, field As DWord, flags As FormatFlags, prefixLen = 0 As DWord, offset = 0 As Long) |
---|
1075 | With sb |
---|
1076 | Dim len = .Length - offset |
---|
1077 | If len < field Then |
---|
1078 | Dim embeddedSize = field - len |
---|
1079 | If flags And LeftSide Then |
---|
1080 | .Append(&h20, embeddedSize) |
---|
1081 | Else |
---|
1082 | If (flags And Zero) <> 0 Then |
---|
1083 | offset += prefixLen |
---|
1084 | If (flags And Blank) Or (flags And Sign) Then |
---|
1085 | offset++ |
---|
1086 | End If |
---|
1087 | .Insert(offset, String$(embeddedSize, "0")) |
---|
1088 | Else |
---|
1089 | .Insert(offset, String$(embeddedSize, " ")) |
---|
1090 | End If |
---|
1091 | End If |
---|
1092 | End If |
---|
1093 | End With |
---|
1094 | End Sub |
---|
1095 | |
---|
1096 | /*! |
---|
1097 | @brief 文字列をprintfの%s相当の変換で書式化する関数。 |
---|
1098 | @author Egtra |
---|
1099 | @date 2007/10/27 |
---|
1100 | @param[in] x 文字列。 |
---|
1101 | @param[in] d 精度、最大の文字数。 |
---|
1102 | @param[in] field フィールド幅。 |
---|
1103 | @param[in] flags 書式フラグ。 |
---|
1104 | @return 書式化された文字列。 |
---|
1105 | */ |
---|
1106 | Function FormatString(x As String, d As DWord, field As DWord, flags As FormatFlags) As String |
---|
1107 | Imports System |
---|
1108 | Dim sb = New System.Text.StringBuilder( |
---|
1109 | Math.Max(Math.Min(x.Length As DWord, d), field) As Long + 1) |
---|
1110 | FormatString(sb, x, d, field, flags) |
---|
1111 | AdjustFieldWidth(sb, field, flags And LeftSide) |
---|
1112 | FormatString = sb.ToString() |
---|
1113 | End Function |
---|
1114 | |
---|
1115 | /*! |
---|
1116 | @brief 文字列をprintfの%s相当の変換で書式化する関数。 |
---|
1117 | @author Egtra |
---|
1118 | @date 2008/03/07 |
---|
1119 | @param[in,out] sb 書式化した文字列を追加するバッファ。 |
---|
1120 | @param[in] x 文字列。 |
---|
1121 | @param[in] d 精度、最大の文字数。 |
---|
1122 | @param[in] field フィールド幅。 |
---|
1123 | @param[in] flags 書式フラグ。 |
---|
1124 | @return 書式化された文字列。 |
---|
1125 | */ |
---|
1126 | Sub FormatString(sb As System.Text.StringBuilder, x As String, d As DWord, field As DWord, flags As FormatFlags) |
---|
1127 | Dim len = sb.Length |
---|
1128 | sb.Append(x, 0, System.Math.Min(x.Length As DWord, d) As Long) |
---|
1129 | AdjustFieldWidth(sb, field, flags And LeftSide, 0, len) |
---|
1130 | End Sub |
---|
1131 | |
---|
1132 | /*! |
---|
1133 | @brief 文字をprintfの%c相当の変換で書式化する関数。 |
---|
1134 | @author Egtra |
---|
1135 | @date 2007/10/27 |
---|
1136 | @param[in] x 文字。 |
---|
1137 | @param[in] d 精度、最大の文字数。 |
---|
1138 | @param[in] field フィールド幅。 |
---|
1139 | @param[in] flags 書式フラグ。 |
---|
1140 | @return 書式化された文字列。 |
---|
1141 | */ |
---|
1142 | Function FormatCharacter(x As Char, d As DWord, field As DWord, flags As FormatFlags) As String |
---|
1143 | Dim sb = New System.Text.StringBuilder(field + 2) |
---|
1144 | FormatCharacter(sb, x, d, field, flags) |
---|
1145 | FormatCharacter = sb.ToString() |
---|
1146 | End Function |
---|
1147 | |
---|
1148 | /*! |
---|
1149 | @brief 文字列をprintfの%s相当の変換で書式化する関数。 |
---|
1150 | @author Egtra |
---|
1151 | @date 2008/03/07 |
---|
1152 | @param[in,out] sb 書式化した文字列を追加するバッファ。 |
---|
1153 | @param[in] x 文字。 |
---|
1154 | @param[in] d 精度、最大の文字数。 |
---|
1155 | @param[in] field フィールド幅。 |
---|
1156 | @param[in] flags 書式フラグ。 |
---|
1157 | @return 書式化された文字列。 |
---|
1158 | */ |
---|
1159 | Sub FormatCharacter(sb As System.Text.StringBuilder, x As Char, d As DWord, field As DWord, flags As FormatFlags) |
---|
1160 | Dim len = sb.Length |
---|
1161 | sb.Append(x) |
---|
1162 | AdjustFieldWidth(sb, field, flags And LeftSide, 0, len) |
---|
1163 | End Sub |
---|
1164 | |
---|
1165 | /*! |
---|
1166 | @author Egtra |
---|
1167 | @date 2007/10/28 |
---|
1168 | */ |
---|
1169 | TypeDef FormatFloatProc = *Sub(sb As System.Text.StringBuilder, x As Double, precision As DWord, fieldWidth As DWord, ByRef flags As FormatFlags) |
---|
1170 | |
---|
1171 | /*! |
---|
1172 | @brief SPrintfから呼ばれる浮動小数点数用書式文字列化関数 |
---|
1173 | @author Egtra |
---|
1174 | @date 2007/10/28 |
---|
1175 | */ |
---|
1176 | Sub FormatFloat(s As System.Text.StringBuilder, formatProc As FormatFloatProc, |
---|
1177 | param As Object, precision As DWord, field As DWord, flags As FormatFlags) |
---|
1178 | |
---|
1179 | Dim x As Double |
---|
1180 | Dim typeName = param.GetType().FullName |
---|
1181 | If typeName = "System.Double" Then |
---|
1182 | x = param As System.Double |
---|
1183 | ElseIf typeName = "System.Single" Then |
---|
1184 | x = param As System.Single |
---|
1185 | End If |
---|
1186 | FormatFloatEx(s, formatProc, x, precision, field, flags) |
---|
1187 | End Sub |
---|
1188 | |
---|
1189 | /*! |
---|
1190 | @brief SPrintfから呼ばれる整数用書式文字列化関数 |
---|
1191 | @author Egtra |
---|
1192 | @date 2007/10/28 |
---|
1193 | */ |
---|
1194 | Sub FormatInteger(s As System.Text.StringBuilder, traits As *IntegerConvertTraits, |
---|
1195 | param As Object, signed As Boolean, typeWidth As Long, precision As DWord, field As DWord, flags As FormatFlags) |
---|
1196 | |
---|
1197 | Dim x As QWord |
---|
1198 | Dim typeName = param.GetType().FullName |
---|
1199 | If typeName = "System.UInt64" Then |
---|
1200 | x = param As System.UInt64 |
---|
1201 | ElseIf typeName = "System.Int64" Then |
---|
1202 | x = (param As System.Int64) As QWord |
---|
1203 | ElseIf typeName = "System.UInt32" Then |
---|
1204 | x = param As System.UInt32 |
---|
1205 | ElseIf typeName = "System.Int32" Then |
---|
1206 | x = (param As System.Int32) As QWord |
---|
1207 | ElseIf typeName = "System.UInt16" Then |
---|
1208 | x = param As System.UInt16 |
---|
1209 | ElseIf typeName = "System.Int16" Then |
---|
1210 | x = (param As System.Int16) As QWord |
---|
1211 | ElseIf typeName = "System.UInt8" Then |
---|
1212 | x = param As System.Byte |
---|
1213 | ElseIf typeName = "System.Int8" Then |
---|
1214 | x = (param As System.SByte) As QWord |
---|
1215 | End If |
---|
1216 | '一旦縮めた後、符号・ゼロ拡張させる。 |
---|
1217 | 'また、64ビット整数なら64ビット変換Traitsを選択する。 |
---|
1218 | If signed Then |
---|
1219 | If typeWidth = 1 Then |
---|
1220 | traits = VarPtr(traits[1]) |
---|
1221 | ElseIf typeWidth = 0 Then |
---|
1222 | x = (((x As DWord) As Long) As Int64) As QWord |
---|
1223 | ElseIf typeWidth = -1 Then |
---|
1224 | x = (((x As Word) As Integer) As Int64) As QWord |
---|
1225 | ElseIf typeWidth = -2 Then |
---|
1226 | x = (((x As Byte) As SByte) As Int64) As QWord |
---|
1227 | End If |
---|
1228 | Else |
---|
1229 | If typeWidth = 1 Then |
---|
1230 | traits = VarPtr(traits[1]) |
---|
1231 | ElseIf typeWidth = 0 Then |
---|
1232 | x = x As DWord |
---|
1233 | ElseIf typeWidth = -1 Then |
---|
1234 | x = x As Word |
---|
1235 | ElseIf typeWidth = -2 Then |
---|
1236 | x = x As Byte |
---|
1237 | End If |
---|
1238 | End If |
---|
1239 | FormatIntegerEx(s, ByVal traits, x, precision, field, flags) |
---|
1240 | End Sub |
---|
1241 | |
---|
1242 | 'Format関数群ここまで |
---|
1243 | '---- |
---|
1244 | |
---|
1245 | /*! |
---|
1246 | @brief 文字列から数値への変換。さらに変換に使われなかった文字列の位置を返す。 |
---|
1247 | @author Egtra |
---|
1248 | @date 2007/11/11 |
---|
1249 | @param[in] s 変換する文字 |
---|
1250 | @param[out] p 変換に使われなかった部分の先頭を指すポインタ |
---|
1251 | @return 変換して得られた数値。変換できなければ0。 |
---|
1252 | */ |
---|
1253 | Function StrToLong(s As *Char, ByRef p As *Char) As Long |
---|
1254 | Dim negative As Boolean |
---|
1255 | Dim i = 0 As Long |
---|
1256 | If s[i] = &h2d Then 'Asc("-") |
---|
1257 | i++ |
---|
1258 | negative = True |
---|
1259 | End If |
---|
1260 | Do |
---|
1261 | Dim c = s[i] |
---|
1262 | If Not CType.IsDigit(c) Then Exit Do |
---|
1263 | StrToLong *= 10 |
---|
1264 | StrToLong += ((c As DWord) And &h0f) As Long |
---|
1265 | i++ |
---|
1266 | Loop |
---|
1267 | If negative Then |
---|
1268 | StrToLong = -StrToLong |
---|
1269 | End If |
---|
1270 | p = VarPtr(s[i]) |
---|
1271 | End Function |
---|
1272 | |
---|
1273 | /*! |
---|
1274 | @brief フィールド幅、精度用の数値読取 |
---|
1275 | @author Egtra |
---|
1276 | @date 2007/11/11 |
---|
1277 | @param[in, out] fmt 読み途中の書式指定 |
---|
1278 | @param[in] params |
---|
1279 | @param[in, out] paramsCount |
---|
1280 | @param[out] ret 読み取った数値。読み取られなかったときの値は不定。 |
---|
1281 | @retval True 読取を行った |
---|
1282 | @retval False 行わなかった |
---|
1283 | fmt[0]が*のときにはparamsから1つ読み取る。 |
---|
1284 | そうでなく、fmtに数字(先頭に-符号があっても可)が並んでいれば、それを読み取る。 |
---|
1285 | */ |
---|
1286 | Function ReadInt(ByRef fmt As *Char, params As *Object, ByRef paramsCount As SIZE_T, ByRef ret As Long) As Boolean |
---|
1287 | If fmt[0] = &h2a Then '* |
---|
1288 | fmt = VarPtr(fmt[1]) 'po |
---|
1289 | ret = params[paramsCount] As System.Int32 |
---|
1290 | paramsCount++ |
---|
1291 | ReadInt = True |
---|
1292 | Else |
---|
1293 | Dim p As *Char |
---|
1294 | ret = StrToLong(fmt, p) |
---|
1295 | If fmt <> p Then |
---|
1296 | fmt = p |
---|
1297 | ReadInt = True |
---|
1298 | Else |
---|
1299 | ReadInt = False |
---|
1300 | End If |
---|
1301 | End If |
---|
1302 | End Function |
---|
1303 | |
---|
1304 | /*! |
---|
1305 | @brief フラグ指定の読み込み |
---|
1306 | @author Egtra |
---|
1307 | @date 2007/10/28 |
---|
1308 | @param[in, out] fmt |
---|
1309 | @param[out] flags |
---|
1310 | @retval True 読み込みが完了した。 |
---|
1311 | @retval False 読み取り中に文字列が終了した(ヌル文字が現れた)。 |
---|
1312 | */ |
---|
1313 | Function ReadFlags(ByRef fmt As *Char, ByRef flags As FormatFlags) As Boolean |
---|
1314 | ReadFlags = False |
---|
1315 | Do |
---|
1316 | Select Case fmt[0] |
---|
1317 | Case &h23 '# |
---|
1318 | flags Or= Alt |
---|
1319 | Case &h30 '0 |
---|
1320 | flags Or= Zero |
---|
1321 | Case &h20 '空白 |
---|
1322 | flags Or= Blank |
---|
1323 | Case &h2b '+ |
---|
1324 | flags Or= Sign |
---|
1325 | Case &h2d '- |
---|
1326 | flags Or = LeftSide |
---|
1327 | Case &h26 '& |
---|
1328 | flags Or= BPrefix |
---|
1329 | Case 0 |
---|
1330 | Exit Function |
---|
1331 | Case Else |
---|
1332 | Exit Do |
---|
1333 | End Select |
---|
1334 | fmt = VarPtr(fmt[1]) 'po |
---|
1335 | Loop |
---|
1336 | ReadFlags = True |
---|
1337 | End Function |
---|
1338 | |
---|
1339 | /*! |
---|
1340 | @brief フィールド幅指定の読み込み |
---|
1341 | @author Egtra |
---|
1342 | @date 2007/10/29 |
---|
1343 | @param[in, out] fmt |
---|
1344 | @param[in] params |
---|
1345 | @param[in, out] paramsCount |
---|
1346 | @param[out] fieldWidth |
---|
1347 | @param[in, out] flags |
---|
1348 | */ |
---|
1349 | Sub ReadFieldWidth(ByRef fmt As *Char, params As *Object, ByRef paramsCount As SIZE_T, |
---|
1350 | ByRef fieldWidth As DWord, ByRef flags As FormatFlags) |
---|
1351 | Dim t As Long |
---|
1352 | If ReadInt(fmt, params, paramsCount, t) Then |
---|
1353 | If t < 0 Then |
---|
1354 | flags Or= LeftSide |
---|
1355 | fieldWidth = -t As DWord |
---|
1356 | Else |
---|
1357 | fieldWidth = t As DWord |
---|
1358 | End If |
---|
1359 | Else |
---|
1360 | fieldWidth = 0 |
---|
1361 | End If |
---|
1362 | End Sub |
---|
1363 | |
---|
1364 | /*! |
---|
1365 | @brief 精度の読み込み |
---|
1366 | @author Egtra |
---|
1367 | @date 2007/10/29 |
---|
1368 | @param[in, out] fmt |
---|
1369 | @param[in] params |
---|
1370 | @param[in, out] paramsCount |
---|
1371 | @return 読み取った精度。指定がなかったときには、DWORD_MAX。 |
---|
1372 | */ |
---|
1373 | Function ReadPrecision(ByRef fmt As *Char, |
---|
1374 | params As *Object, ByRef paramsCount As SIZE_T) As DWord |
---|
1375 | |
---|
1376 | If fmt[0] = &h2e Then '. |
---|
1377 | fmt = VarPtr(fmt[1]) 'po |
---|
1378 | Dim t As Long |
---|
1379 | ReadPrecision = 0 |
---|
1380 | If ReadInt(fmt, params, paramsCount, t) Then |
---|
1381 | If t > 0 Then |
---|
1382 | ReadPrecision = t As DWord |
---|
1383 | End If |
---|
1384 | End If |
---|
1385 | Else |
---|
1386 | ReadPrecision = DWORD_MAX |
---|
1387 | End If |
---|
1388 | End Function |
---|
1389 | |
---|
1390 | #ifdef _WIN64 |
---|
1391 | Const PtrLength = 1 |
---|
1392 | #else |
---|
1393 | Const PtrLength = 0 |
---|
1394 | #endif |
---|
1395 | |
---|
1396 | /*! |
---|
1397 | @biref 長さ指定の読み込み |
---|
1398 | @author Egtra |
---|
1399 | @date 2007/10/29 |
---|
1400 | @param[in, out] fmt |
---|
1401 | @param[out] lengthSpec |
---|
1402 | */ |
---|
1403 | Sub ReadLength(ByRef fmt As *Char, ByRef lengthSpec As Long) |
---|
1404 | Do |
---|
1405 | Select Case fmt[0] |
---|
1406 | Case &h6c 'l |
---|
1407 | lengthSpec++ |
---|
1408 | Case &h68 'h |
---|
1409 | lengthSpec-- |
---|
1410 | Case &h6a 'j (u)intmax_t = QWord, Int64 |
---|
1411 | lengthSpec = 1 |
---|
1412 | Case &h74 't ptrdiff_t |
---|
1413 | lengthSpec = PtrLength |
---|
1414 | Case &h7a 'z (s)size_t |
---|
1415 | lengthSpec = PtrLength |
---|
1416 | Case &h70 'p VoidPtr 本来は変換指定子だが、ここで先読み |
---|
1417 | lengthSpec = PtrLength |
---|
1418 | Exit Sub 'fmtを進められると困るので、ここで脱出 |
---|
1419 | Case Else |
---|
1420 | Exit Sub |
---|
1421 | End Select |
---|
1422 | fmt = VarPtr(fmt[1]) 'po |
---|
1423 | Loop |
---|
1424 | End Sub |
---|
1425 | |
---|
1426 | /*! |
---|
1427 | @brief efg変換用に、精度が指定されていないときに既定の精度を設定する。 |
---|
1428 | @auther Egtra |
---|
1429 | @date 2008/03/07 |
---|
1430 | */ |
---|
1431 | Sub AdjustPrecision(ByRef precision As DWord) |
---|
1432 | If precision = DWORD_MAX Then |
---|
1433 | precision = 6 |
---|
1434 | End If |
---|
1435 | End Sub |
---|
1436 | |
---|
1437 | /*! |
---|
1438 | @biref Cのsprintfのような書式文字列出力関数 |
---|
1439 | @author Egtra |
---|
1440 | @date 2007/10/27 |
---|
1441 | @param[in] format 書式文字列。詳細は開発Wiki参照。 |
---|
1442 | @param[in, out] params 変換対象の配列。n = 0のときにはNULLも可。 |
---|
1443 | @param[in] n paramsの個数。 |
---|
1444 | @return 書式化された文字列。 |
---|
1445 | @todo %nへの対応 |
---|
1446 | */ |
---|
1447 | Function SPrintf(format As String, params As *Object, n As SIZE_T) As String |
---|
1448 | Dim i = 0 As SIZE_T |
---|
1449 | Dim paramsCount = 0 As SIZE_T |
---|
1450 | Dim fmt = StrPtr(format) |
---|
1451 | Dim s = New System.Text.StringBuilder |
---|
1452 | Do |
---|
1453 | Dim last = format.Length - (((fmt - StrPtr(format)) \ SizeOf (Char)) As LONG_PTR) As Long 'po |
---|
1454 | Dim pos = ChrFind(fmt, last, &h25 As Char) As Long '&h25 = % |
---|
1455 | If pos = -1 Then |
---|
1456 | s.Append(fmt, 0, last) |
---|
1457 | Exit Do |
---|
1458 | End If |
---|
1459 | '%以前の部分 |
---|
1460 | s.Append(fmt, 0, pos) |
---|
1461 | fmt = VarPtr(fmt[pos + 1]) 'po |
---|
1462 | 'フラグの読取 |
---|
1463 | Dim flags = None As FormatFlags |
---|
1464 | If ReadFlags(fmt, flags) = False Then |
---|
1465 | Exit Do |
---|
1466 | End If |
---|
1467 | 'フィールド幅 |
---|
1468 | Dim fieldWidth As DWord |
---|
1469 | ReadFieldWidth(fmt, params, i, fieldWidth, flags) |
---|
1470 | '精度 |
---|
1471 | Dim precision = ReadPrecision(fmt, params, i) |
---|
1472 | '幅指定の読取 |
---|
1473 | Dim typeWidth As Long |
---|
1474 | ReadLength(fmt, typeWidth) |
---|
1475 | |
---|
1476 | Select Case fmt[0] |
---|
1477 | Case &h64 'd |
---|
1478 | FormatInteger(s, TraitsIntegerD, params[i], True, typeWidth, precision, fieldWidth, flags) |
---|
1479 | Case &h69 'i |
---|
1480 | FormatInteger(s, TraitsIntegerD, params[i], True, typeWidth, precision, fieldWidth, flags) |
---|
1481 | Case &h75 'u |
---|
1482 | FormatInteger(s, TraitsIntegerU, params[i], False, typeWidth, precision, fieldWidth, flags) |
---|
1483 | Case &h4f 'O |
---|
1484 | flags Or= Cap |
---|
1485 | Goto *O |
---|
1486 | Case &h6f 'o |
---|
1487 | *O |
---|
1488 | FormatInteger(s, TraitsIntegerO, params[i], False, typeWidth, precision, fieldWidth, flags) |
---|
1489 | Case &h58 'X |
---|
1490 | flags Or= Cap |
---|
1491 | Goto *X |
---|
1492 | Case &h78 'x |
---|
1493 | *X |
---|
1494 | FormatInteger(s, TraitsIntegerX, params[i], False, typeWidth, precision, fieldWidth, flags) |
---|
1495 | '現状ではVoidPtrを引数にする手段は無いはず |
---|
1496 | ' Case &h58 'p |
---|
1497 | ' FormatInteger(s, TraitsIntegerX, params[i], False, typeWidth, precision, fieldWidth, flags Or Cap) |
---|
1498 | Case &h45 'E |
---|
1499 | flags Or= Cap |
---|
1500 | Goto *E |
---|
1501 | Case &h65 'e |
---|
1502 | *E |
---|
1503 | AdjustPrecision(precision) |
---|
1504 | FormatFloat(s, AddressOf(FormatFloatE_Convert), params[i], precision, fieldWidth, flags) |
---|
1505 | Case &h46 'F |
---|
1506 | flags Or= Cap |
---|
1507 | Goto *F |
---|
1508 | Case &h66 'f |
---|
1509 | *F |
---|
1510 | AdjustPrecision(precision) |
---|
1511 | FormatFloat(s, AddressOf(FormatFloatF_Convert), params[i], precision, fieldWidth, flags) |
---|
1512 | Case &h47 'G |
---|
1513 | flags Or= Cap |
---|
1514 | Goto *G |
---|
1515 | Case &h67 'g |
---|
1516 | *G |
---|
1517 | AdjustPrecision(precision) |
---|
1518 | FormatFloat(s, AddressOf(FormatFloatG_Convert), params[i], precision, fieldWidth, flags) |
---|
1519 | Case &h41 'A |
---|
1520 | flags Or= Cap |
---|
1521 | Goto *A |
---|
1522 | Case &h61 'a |
---|
1523 | *A |
---|
1524 | FormatFloat(s, AddressOf(FormatFloatA), params[i], precision, fieldWidth, flags) |
---|
1525 | Case &h73 's |
---|
1526 | FormatString(s, params[i] As String, precision, fieldWidth, flags) |
---|
1527 | Case &h63 'c |
---|
1528 | FormatCharacter(s, params[i] As BoxedStrChar, precision, fieldWidth, flags) |
---|
1529 | ' Case &h6e 'n |
---|
1530 | Case &h25 '% |
---|
1531 | s.Append(&h25 As Char) |
---|
1532 | i-- |
---|
1533 | Case 0 |
---|
1534 | Exit Do |
---|
1535 | End Select |
---|
1536 | fmt = VarPtr(fmt[1]) 'po |
---|
1537 | i++ |
---|
1538 | Loop |
---|
1539 | SPrintf = s.ToString |
---|
1540 | End Function |
---|
1541 | |
---|
1542 | End Namespace 'Detail |
---|
1543 | |
---|
1544 | /*! |
---|
1545 | @brief Cのsprintfのような書式化関数10引数版 |
---|
1546 | @author Egtra |
---|
1547 | @date 2007/10/27 |
---|
1548 | @param[in] format 書式指定 |
---|
1549 | @param[in] paramN 引数 |
---|
1550 | @return 書式化された文字列 |
---|
1551 | */ |
---|
1552 | |
---|
1553 | Function SPrintf(format As String, param0 As Object, |
---|
1554 | param1 As Object, param2 As Object, param3 As Object, |
---|
1555 | param4 As Object, param5 As Object, param6 As Object, |
---|
1556 | param7 As Object, param8 As Object, param9 As Object) As String |
---|
1557 | |
---|
1558 | Dim params = VarPtr(param0) As *Object |
---|
1559 | |
---|
1560 | SPrintf = ActiveBasic.Strings.Detail.SPrintf(format, params, 10) |
---|
1561 | End Function |
---|
1562 | |
---|
1563 | /*! |
---|
1564 | @brief Cのsprintfのような書式化関数9引数版 |
---|
1565 | @author Egtra |
---|
1566 | @date 2007/10/27 |
---|
1567 | @param[in] format 書式指定 |
---|
1568 | @param[in] paramN 引数 |
---|
1569 | @return 書式化された文字列 |
---|
1570 | */ |
---|
1571 | Function SPrintf(format As String, param0 As Object, |
---|
1572 | param1 As Object, param2 As Object, param3 As Object, |
---|
1573 | param4 As Object, param5 As Object, param6 As Object, |
---|
1574 | param7 As Object, param8 As Object) As String |
---|
1575 | |
---|
1576 | Dim params = VarPtr(param0) As *Object |
---|
1577 | |
---|
1578 | SPrintf = ActiveBasic.Strings.Detail.SPrintf(format, params, 9) |
---|
1579 | End Function |
---|
1580 | |
---|
1581 | /*! |
---|
1582 | @brief Cのsprintfのような書式化関数8引数版 |
---|
1583 | @author Egtra |
---|
1584 | @date 2007/10/27 |
---|
1585 | @param[in] format 書式指定 |
---|
1586 | @param[in] paramN 引数 |
---|
1587 | @return 書式化された文字列 |
---|
1588 | */ |
---|
1589 | Function SPrintf(format As String, param0 As Object, |
---|
1590 | param1 As Object, param2 As Object, param3 As Object, |
---|
1591 | param4 As Object, param5 As Object, param6 As Object, |
---|
1592 | param7 As Object) As String |
---|
1593 | |
---|
1594 | Dim params = VarPtr(param0) As *Object |
---|
1595 | |
---|
1596 | SPrintf = ActiveBasic.Strings.Detail.SPrintf(format, params, 8) |
---|
1597 | End Function |
---|
1598 | |
---|
1599 | /*! |
---|
1600 | @brief Cのsprintfのような書式化関数7引数版 |
---|
1601 | @author Egtra |
---|
1602 | @date 2007/10/27 |
---|
1603 | @param[in] format 書式指定 |
---|
1604 | @param[in] paramN 引数 |
---|
1605 | @return 書式化された文字列 |
---|
1606 | */ |
---|
1607 | Function SPrintf(format As String, param0 As Object, |
---|
1608 | param1 As Object, param2 As Object, param3 As Object, |
---|
1609 | param4 As Object, param5 As Object, param6 As Object) As String |
---|
1610 | |
---|
1611 | Dim params = VarPtr(param0) As *Object |
---|
1612 | |
---|
1613 | SPrintf = ActiveBasic.Strings.Detail.SPrintf(format, params, 7) |
---|
1614 | End Function |
---|
1615 | |
---|
1616 | /*! |
---|
1617 | @brief Cのsprintfのような書式化関数6引数版 |
---|
1618 | @author Egtra |
---|
1619 | @date 2007/10/27 |
---|
1620 | @param[in] format 書式指定 |
---|
1621 | @param[in] paramN 引数 |
---|
1622 | @return 書式化された文字列 |
---|
1623 | */ |
---|
1624 | Function SPrintf(format As String, param0 As Object, |
---|
1625 | param1 As Object, param2 As Object, param3 As Object, |
---|
1626 | param4 As Object, param5 As Object) As String |
---|
1627 | |
---|
1628 | Dim params = VarPtr(param0) As *Object |
---|
1629 | |
---|
1630 | SPrintf = ActiveBasic.Strings.Detail.SPrintf(format, params, 6) |
---|
1631 | End Function |
---|
1632 | |
---|
1633 | /*! |
---|
1634 | @brief Cのsprintfのような書式化関数5引数版 |
---|
1635 | @author Egtra |
---|
1636 | @date 2007/10/27 |
---|
1637 | @param[in] format 書式指定 |
---|
1638 | @param[in] paramN 引数 |
---|
1639 | @return 書式化された文字列 |
---|
1640 | */ |
---|
1641 | Function SPrintf(format As String, param0 As Object, |
---|
1642 | param1 As Object, param2 As Object, param3 As Object, |
---|
1643 | param4 As Object) As String |
---|
1644 | |
---|
1645 | Dim params = VarPtr(param0) As *Object |
---|
1646 | |
---|
1647 | SPrintf = ActiveBasic.Strings.Detail.SPrintf(format, params, 5) |
---|
1648 | End Function |
---|
1649 | |
---|
1650 | /*! |
---|
1651 | @brief Cのsprintfのような書式化関数4引数版 |
---|
1652 | @author Egtra |
---|
1653 | @date 2007/10/27 |
---|
1654 | @param[in] format 書式指定 |
---|
1655 | @param[in] paramN 引数 |
---|
1656 | @return 書式化された文字列 |
---|
1657 | */ |
---|
1658 | Function SPrintf(format As String, param0 As Object, |
---|
1659 | param1 As Object, param2 As Object, param3 As Object) As String |
---|
1660 | |
---|
1661 | Dim params = VarPtr(param0) As *Object |
---|
1662 | |
---|
1663 | SPrintf = ActiveBasic.Strings.Detail.SPrintf(format, params, 4) |
---|
1664 | End Function |
---|
1665 | |
---|
1666 | /*! |
---|
1667 | @brief Cのsprintfのような書式化関数3引数版 |
---|
1668 | @author Egtra |
---|
1669 | @date 2007/10/27 |
---|
1670 | @param[in] format 書式指定 |
---|
1671 | @param[in] paramN 引数 |
---|
1672 | @return 書式化された文字列 |
---|
1673 | */ |
---|
1674 | Function SPrintf(format As String, param0 As Object, |
---|
1675 | param1 As Object, param2 As Object) As String |
---|
1676 | |
---|
1677 | Dim params = VarPtr(param0) As *Object |
---|
1678 | |
---|
1679 | SPrintf = ActiveBasic.Strings.Detail.SPrintf(format, params, 3) |
---|
1680 | End Function |
---|
1681 | |
---|
1682 | /*! |
---|
1683 | @brief Cのsprintfのような書式化関数2引数版 |
---|
1684 | @author Egtra |
---|
1685 | @date 2007/10/27 |
---|
1686 | @param[in] format 書式指定 |
---|
1687 | @param[in] paramN 引数 |
---|
1688 | @return 書式化された文字列 |
---|
1689 | */ |
---|
1690 | Function SPrintf(format As String, param0 As Object, |
---|
1691 | param1 As Object) As String |
---|
1692 | |
---|
1693 | Dim params = VarPtr(param0) As *Object |
---|
1694 | |
---|
1695 | SPrintf = ActiveBasic.Strings.Detail.SPrintf(format, params, 2) |
---|
1696 | End Function |
---|
1697 | |
---|
1698 | /*! |
---|
1699 | @brief Cのsprintfのような書式化関数1引数版 |
---|
1700 | @author Egtra |
---|
1701 | @date 2007/10/27 |
---|
1702 | @param[in] format 書式指定 |
---|
1703 | @param[in] paramN 引数 |
---|
1704 | @return 書式化された文字列 |
---|
1705 | */ |
---|
1706 | Function SPrintf(format As String, param0 As Object) As String |
---|
1707 | Dim params = VarPtr(param0) As *Object |
---|
1708 | SPrintf = ActiveBasic.Strings.Detail.SPrintf(format, params, 1) |
---|
1709 | End Function |
---|
1710 | |
---|
1711 | /*! |
---|
1712 | @brief Cのsprintfのような書式化関数0引数版 |
---|
1713 | @author Egtra |
---|
1714 | @date 2007/10/27 |
---|
1715 | @param[in] format 書式指定 |
---|
1716 | @param[in] paramN 引数 |
---|
1717 | @return 書式化された文字列 |
---|
1718 | */ |
---|
1719 | Function SPrintf(format As String) As String |
---|
1720 | SPrintf = ActiveBasic.Strings.Detail.SPrintf(format, 0, 0) |
---|
1721 | End Function |
---|
1722 | |
---|
1723 | End Namespace 'Strings |
---|
1724 | End Namespace 'ActiveBasic |
---|