1 | 'Classes/ActiveBasic/Strings/SPrintF.ab |
---|
2 | |
---|
3 | Namespace ActiveBasic |
---|
4 | Namespace Strings |
---|
5 | |
---|
6 | Namespace Detail |
---|
7 | |
---|
8 | /*! |
---|
9 | @brief 浮動小数点数を文字列化する低水準な関数。符号、指数、仮数に分けて出力。 |
---|
10 | @author Egtra |
---|
11 | @date 2007/09/18 |
---|
12 | @param[in] x 文字列化する浮動小数点数 |
---|
13 | @param[out] e 指数 |
---|
14 | @param[out] sign 符号 |
---|
15 | @return 仮数 |
---|
16 | 仮数は1の位から下へ17桁で、小数点を含まない。そのため、誤差を無視すればVal(仮数) * 10 ^ (e - 17) = Abs(x)が成り立つ。 |
---|
17 | |
---|
18 | xに無限大、非数を渡した場合の動作は未定義。 |
---|
19 | */ |
---|
20 | Function FloatToChars(x As Double, ByRef e As Long, ByRef sign As Boolean) As String |
---|
21 | Imports System |
---|
22 | |
---|
23 | '0を弾く |
---|
24 | If x = 0 Then |
---|
25 | If GetQWord(VarPtr(x) As *QWord) And &h8000000000000000 Then |
---|
26 | sign = True |
---|
27 | Else |
---|
28 | sign = False |
---|
29 | End If |
---|
30 | |
---|
31 | e = 0 |
---|
32 | FloatToChars = "00000000000000000" |
---|
33 | Exit Function |
---|
34 | End If |
---|
35 | |
---|
36 | '符号の判断(同時に符号を取り除く) |
---|
37 | If x < 0 Then |
---|
38 | sign = True |
---|
39 | x = -x |
---|
40 | Else |
---|
41 | sign = False |
---|
42 | End If |
---|
43 | |
---|
44 | '1e16 <= x < 1e17へ正規化 |
---|
45 | '(元のx) = (正規化後のx) ^ (d - 17)である。 |
---|
46 | Dim d = Math.Floor(Math.Log10(x)) As Long |
---|
47 | If d < 16 Then |
---|
48 | x *= ipow(10, +17 - d) |
---|
49 | ElseIf d > 16 Then |
---|
50 | x /= ipow(10, -17 + d) |
---|
51 | End If |
---|
52 | |
---|
53 | '補正 |
---|
54 | While x < 1e16 |
---|
55 | x *= 10 |
---|
56 | d-- |
---|
57 | Wend |
---|
58 | While x >= 1e17 |
---|
59 | x /= 10 |
---|
60 | d++ |
---|
61 | Wend |
---|
62 | |
---|
63 | d-- |
---|
64 | e = d |
---|
65 | |
---|
66 | FloatToChars = FormatIntegerLU((x As Int64) As QWord, 17, 0, None) |
---|
67 | End Function |
---|
68 | |
---|
69 | /*! |
---|
70 | @brief 書式化関数群で使用するフラグ。 |
---|
71 | @author Egtra |
---|
72 | @date 2007/09/18 |
---|
73 | */ |
---|
74 | Const Enum FormatFlags |
---|
75 | '! 何も指定がない。 |
---|
76 | None = &h0 |
---|
77 | /*! |
---|
78 | 符号、+。符号付変換[diAaEeFfGg]のとき、正の値でも符号を付ける。 |
---|
79 | AdjustFieldWidthの仕様から、Format関数郡内からAdjustFieldWidthにかけて、 |
---|
80 | 単に数値が符号付である(負の値である)ことを示す意味でも用いられる。 |
---|
81 | */ |
---|
82 | Sign = &h1 |
---|
83 | /*! 空白、空白文字。 |
---|
84 | 符号付変換[diAaEeFfGg]のとき、正の値ならば符号分の空白を開ける。Signが立っているときには無視される。 |
---|
85 | */ |
---|
86 | Blank = &h2 |
---|
87 | /*! ゼロ、0。 |
---|
88 | [diouXxAaEeFfGg]で、フィールドの空きを0で埋める。leftが立っているときには無視される。 |
---|
89 | */ |
---|
90 | Zero = &h4 |
---|
91 | '! 左揃え、-。フィールド内で左揃えにする。 |
---|
92 | Left = &h8 |
---|
93 | /*! 代替表記、#。 |
---|
94 | <ul> |
---|
95 | <li>[OoXx]では、値が0でない場合、先頭に0、0xを付ける。</ul> |
---|
96 | <li>[AaEeFfGg]では、精度0でも小数点を付ける。</ul> |
---|
97 | <li>[Gg]では、それに加え、小数部末尾の0の省略を行わないようにする。</ul> |
---|
98 | </ul> |
---|
99 | */ |
---|
100 | Alt = &h10 |
---|
101 | '! 大文字。使用するアルファベットを大文字にする。[aefgx]を[AEFGX]化する。 |
---|
102 | Cap = &h20 |
---|
103 | |
---|
104 | /*! |
---|
105 | 内部処理用に予約。 |
---|
106 | @note Minusとして使用されている。 |
---|
107 | */ |
---|
108 | Reserved = &h80000000 |
---|
109 | End Enum |
---|
110 | |
---|
111 | /*! |
---|
112 | @brief 浮動小数点数をprintfの%e, %E(指数形式、十進法)相当の変換で文字列化する関数。 |
---|
113 | @author Egtra |
---|
114 | @date 2007/09/18 |
---|
115 | @param[in] x 文字列化する浮動小数点数値。 |
---|
116 | @param[in] d 精度。小数点以下の桁数。DWORD_MAXのとき、指定なしとして既定値6となる。 |
---|
117 | @param[in] field フィールド幅。 |
---|
118 | @param[in] flags 書式フラグ。 |
---|
119 | @return xの文字列表現 |
---|
120 | |
---|
121 | @todo 他の実装での末尾桁の扱いを調べる(このコードでは何もしていないので切捨となっている)。 |
---|
122 | */ |
---|
123 | Function FormatFloatE(x As Double, d As DWord, field As DWord, flags As FormatFlags) As String |
---|
124 | If d = DWORD_MAX Then |
---|
125 | d = 6 |
---|
126 | End If |
---|
127 | |
---|
128 | Dim e As Long, negative As Boolean |
---|
129 | Dim s = FloatToChars(x, e, negative) |
---|
130 | |
---|
131 | Dim sb = New System.Text.StringBuilder |
---|
132 | With sb |
---|
133 | |
---|
134 | AppendSign(sb, negative, flags) |
---|
135 | |
---|
136 | .Append(s[0]) |
---|
137 | |
---|
138 | If (flags And Alt) Or d > 0 Then |
---|
139 | .Append(".") |
---|
140 | Dim outputLen = s.Length - 1 |
---|
141 | If outputLen >= d Then |
---|
142 | .Append(s, 1, d) |
---|
143 | Else 'sで用意された桁が指定された精度より少ないとき |
---|
144 | .Append(s, 1, outputLen) |
---|
145 | .Append(&h30 As StrChar, d - outputLen) '足りない桁は0埋め |
---|
146 | End If |
---|
147 | End If |
---|
148 | |
---|
149 | If flags And Cap Then |
---|
150 | .Append("E") |
---|
151 | Else |
---|
152 | .Append("e") |
---|
153 | End If |
---|
154 | |
---|
155 | .Append(FormatIntegerD(e, 2, 0, Sign Or Zero)) |
---|
156 | |
---|
157 | AdjustFieldWidth(sb, field, flags) |
---|
158 | End With |
---|
159 | FormatFloatE = sb.ToString() |
---|
160 | End Function |
---|
161 | |
---|
162 | /*! |
---|
163 | @brief 浮動小数点数をprintfの%f(小数形式、十進法)相当の変換で文字列化する関数。 |
---|
164 | @author Egtra |
---|
165 | @date 2007/10/23 |
---|
166 | @param[in] x 文字列化する浮動小数点数値。 |
---|
167 | @param[in] precision 精度。小数点以下の桁数。DWORD_MAXのとき、指定なしとして既定値6となる。 |
---|
168 | @param[in] field フィールド幅。 |
---|
169 | @param[in] flags 書式フラグ。 |
---|
170 | @return xの文字列表現 |
---|
171 | */ |
---|
172 | Function FormatFloatF(x As Double, precision As DWord, field As DWord, flags As FormatFlags) As String |
---|
173 | If precision = DWORD_MAX Then |
---|
174 | precision = 6 |
---|
175 | End If |
---|
176 | |
---|
177 | Dim e As Long, negative As Boolean |
---|
178 | Dim s = FloatToChars(x, e, negative) |
---|
179 | |
---|
180 | Dim sb = New System.Text.StringBuilder |
---|
181 | With sb |
---|
182 | AppendSign(sb, negative, flags) |
---|
183 | |
---|
184 | Dim intPartLen = e + 1 |
---|
185 | Dim outputDigit = 0 As DWord |
---|
186 | If intPartLen >= 17 Then |
---|
187 | '有効桁が全て整数部に収まる場合 |
---|
188 | .Append(s) |
---|
189 | .Append(&h30 As StrChar, intPartLen - 17) |
---|
190 | outputDigit = 17 |
---|
191 | ElseIf intPartLen > 0 Then |
---|
192 | '有効桁の一部が整数部にかかる場合 |
---|
193 | .Append(s, 0, intPartLen) |
---|
194 | outputDigit = intPartLen |
---|
195 | Else |
---|
196 | '有効桁が全く整数部にかからない場合 |
---|
197 | .Append(&h30 As StrChar) |
---|
198 | End If |
---|
199 | |
---|
200 | If precision > 0 Or (flags And Alt) Then |
---|
201 | .Append(".") |
---|
202 | |
---|
203 | Dim lastDigit = s.Length - outputDigit |
---|
204 | If lastDigit >= precision Then '変換して得られた文字列の桁数が精度以上ある場合 |
---|
205 | Dim zeroDigit = 0 |
---|
206 | If intPartLen < 0 Then |
---|
207 | '1.23e-4 = 0.000123のように指数が負のため小数点以下に0が続く場合 |
---|
208 | zeroDigit = System.Math.Min(-intPartLen As DWord, precision) |
---|
209 | .Append(&h30 As StrChar, zeroDigit As Long) |
---|
210 | End If |
---|
211 | .Append(s, outputDigit, (precision - zeroDigit) As Long) |
---|
212 | Else |
---|
213 | .Append(s, outputDigit, lastDigit) |
---|
214 | .Append(&h30 As StrChar, (precision - lastDigit) As Long) '残りの桁は0埋め |
---|
215 | End If |
---|
216 | End If |
---|
217 | AdjustFieldWidth(sb, field, flags) |
---|
218 | End With |
---|
219 | FormatFloatF = sb.ToString() |
---|
220 | End Function |
---|
221 | |
---|
222 | /*! |
---|
223 | @brief 先頭に符号もしくはその分の空白を出力する。FormatFloat用。 |
---|
224 | @author Egtra |
---|
225 | @date 2007/10/23 |
---|
226 | @param[in, out] sb 出力先 |
---|
227 | @param[in] negative 符号 |
---|
228 | @param[in, out] flags フラグ。negative = Trueなら、Signを立てて返す。 |
---|
229 | */ |
---|
230 | Sub AppendSign(sb As System.Text.StringBuilder, negative As Boolean, ByRef flags As FormatFlags) |
---|
231 | With sb |
---|
232 | If negative Then |
---|
233 | .Append("-") |
---|
234 | flags Or= Sign |
---|
235 | Else |
---|
236 | If flags And Sign Then |
---|
237 | .Append("+") |
---|
238 | ElseIf flags And Blank Then |
---|
239 | .Append(" ") |
---|
240 | End If |
---|
241 | End If |
---|
242 | End With |
---|
243 | End Sub |
---|
244 | |
---|
245 | /*! |
---|
246 | @brief DWordの最大値4294967295の文字数 - 1。FormatIntegerU内で使用。 |
---|
247 | @author Egtra |
---|
248 | @date 2007/09/18 |
---|
249 | */ |
---|
250 | Const MaxSizeU = 9 |
---|
251 | |
---|
252 | /*! |
---|
253 | @brief 符号無し整数をprintfの%u(十進法表現)相当の変換で文字列化する関数。 |
---|
254 | @author Egtra |
---|
255 | @date 2007/09/18 |
---|
256 | @param[in] x 文字列化する整数値。 |
---|
257 | @param[in] d 精度、最小限表示される桁数。DWORD_MAXのとき、指定なしとして、既定値1となる。 |
---|
258 | @param[in] field フィールド幅。 |
---|
259 | @param[in] flags 書式フラグ。 |
---|
260 | @return xの文字列表現 |
---|
261 | */ |
---|
262 | Function FormatIntegerU(x As DWord, d As DWord, field As DWord, flags As FormatFlags) As String |
---|
263 | Return FormatIntegerEx(TraitsIntegerDU, x, d, field, flags And (Not (Sign Or Blank))) |
---|
264 | End Function |
---|
265 | |
---|
266 | /*! |
---|
267 | @brief FormatIntegerUのQWord版 |
---|
268 | @author Egtra |
---|
269 | @date 2007/10/26 |
---|
270 | */ |
---|
271 | Function FormatIntegerLU(x As QWord, d As DWord, field As DWord, flags As FormatFlags) As String |
---|
272 | Return FormatIntegerEx(TraitsIntegerLDU, x, d, field, flags And (Not (Sign Or Blank))) |
---|
273 | End Function |
---|
274 | |
---|
275 | /*! |
---|
276 | @brief 符号有り整数をprintfの%d(十進法表現)相当の変換で文字列化する関数。 |
---|
277 | @author Egtra |
---|
278 | @date 2007/10/13 |
---|
279 | @param[in] x 文字列化する整数値。 |
---|
280 | @param[in] d 精度、最小限表示される桁数。DWORD_MAXのとき、指定なしとして、既定値1となる。 |
---|
281 | @param[in] field フィールド幅。 |
---|
282 | @param[in] flags 書式フラグ。 |
---|
283 | @return xの文字列表現 |
---|
284 | */ |
---|
285 | Function FormatIntegerD(x As Long, d As DWord, field As DWord, flags As FormatFlags) As String |
---|
286 | Dim unsignedX As DWord |
---|
287 | If x < 0 Then |
---|
288 | unsignedX = (-x) As DWord |
---|
289 | flags Or= Minus |
---|
290 | Else |
---|
291 | unsignedX = x As DWord |
---|
292 | End If |
---|
293 | |
---|
294 | Return FormatIntegerEx(TraitsIntegerDU, unsignedX, d, field, flags) |
---|
295 | End Function |
---|
296 | |
---|
297 | /*! |
---|
298 | @brief FormatIntegerDのInt64版 |
---|
299 | @author Egtra |
---|
300 | @date 2007/10/26 |
---|
301 | */ |
---|
302 | Function FormatIntegerLD(x As Int64, d As DWord, field As DWord, flags As FormatFlags) As String |
---|
303 | Dim unsignedX As QWord |
---|
304 | If x < 0 Then |
---|
305 | unsignedX = (-x) As QWord |
---|
306 | flags Or= Minus |
---|
307 | Else |
---|
308 | unsignedX = x As QWord |
---|
309 | End If |
---|
310 | |
---|
311 | Return FormatIntegerEx(TraitsIntegerLDU, unsignedX, d, field, flags) |
---|
312 | End Function |
---|
313 | |
---|
314 | /*! |
---|
315 | @author Egtra |
---|
316 | @date 2007/10/26 |
---|
317 | */ |
---|
318 | Dim TraitsIntegerDU As IntegerConvertTraits |
---|
319 | With TraitsIntegerDU |
---|
320 | .Convert = AddressOf(IntegerDU_Convert) |
---|
321 | .Prefix = AddressOf(IntegerDU_Prefix) |
---|
322 | .MaxSize = MaxSizeU |
---|
323 | End With |
---|
324 | |
---|
325 | /*! |
---|
326 | @author Egtra |
---|
327 | @date 2007/10/26 |
---|
328 | */ |
---|
329 | Dim TraitsIntegerLDU As IntegerConvertTraits |
---|
330 | With TraitsIntegerLDU |
---|
331 | .Convert = AddressOf(IntegerLDU_Convert) |
---|
332 | .Prefix = AddressOf(IntegerDU_Prefix) |
---|
333 | .MaxSize = MaxSizeLU |
---|
334 | End With |
---|
335 | |
---|
336 | /*! |
---|
337 | @brief 負数を表すフラグ。FormatIntegerD, LDからIntegerDU_Prefixまでの内部処理用。 |
---|
338 | @author Egtra |
---|
339 | @date 2007/10/26 |
---|
340 | */ |
---|
341 | Const Minus = Reserved |
---|
342 | |
---|
343 | /*! |
---|
344 | @author Egtra |
---|
345 | @date 2007/10/26 |
---|
346 | */ |
---|
347 | Function IntegerDU_Convert(buf As *StrChar, xq As QWord, flags As FormatFlags) As DWord |
---|
348 | Dim x = xq As DWord |
---|
349 | Dim i = MaxSizeU |
---|
350 | While x <> 0 |
---|
351 | buf[i] = (x As Int64 Mod 10 + &h30) As StrChar 'Int64への型変換は#117対策 |
---|
352 | x \= 10 |
---|
353 | i-- |
---|
354 | Wend |
---|
355 | Return i |
---|
356 | End Function |
---|
357 | |
---|
358 | /*! |
---|
359 | @brief IntegerDU_ConvertのQWord版 |
---|
360 | @author Egtra |
---|
361 | @date 2007/10/26 |
---|
362 | @bug #117のため、現在Int64の最大値を超える値を正しく処理できない。 |
---|
363 | */ |
---|
364 | Function IntegerLDU_Convert(buf As *StrChar, x As QWord, flags As FormatFlags) As DWord |
---|
365 | Dim i = MaxSizeLU |
---|
366 | While x <> 0 |
---|
367 | buf[i] = (x As Int64 Mod 10 + &h30) As StrChar 'Int64への型変換は#117対策 |
---|
368 | x \= 10 |
---|
369 | i-- |
---|
370 | Wend |
---|
371 | Return i |
---|
372 | End Function |
---|
373 | |
---|
374 | /*! |
---|
375 | @author Egtra |
---|
376 | @date 2007/10/26 |
---|
377 | */ |
---|
378 | Function IntegerDU_Prefix(x As QWord, flags As FormatFlags) As String |
---|
379 | If flags And Minus Then |
---|
380 | IntegerDU_Prefix = "-" |
---|
381 | ElseIf flags And Sign Then |
---|
382 | IntegerDU_Prefix = "+" |
---|
383 | ElseIf flags And Blank Then |
---|
384 | IntegerDU_Prefix = " " |
---|
385 | End If |
---|
386 | End Function |
---|
387 | |
---|
388 | /*! |
---|
389 | @brief DWordの最大値の八進法表現37777777777の文字数 - 1 + 1。IntegerO_Convert内で使用。 |
---|
390 | @author Egtra |
---|
391 | @date 2007/10/19 |
---|
392 | 上の式で1を加えているのは、八進接頭辞の分。 |
---|
393 | */ |
---|
394 | Const MaxSizeO = 11 |
---|
395 | |
---|
396 | /*! |
---|
397 | @brief QWordの最大値の八進法表現1777777777777777777777の文字数 - 1 + 1。IntegerO_Convert内で使用。 |
---|
398 | @author Egtra |
---|
399 | @date 2007/10/26 |
---|
400 | 上の式で1を加えているのは、八進接頭辞の分。 |
---|
401 | */ |
---|
402 | Const MaxSizeLO = 22 |
---|
403 | |
---|
404 | /*! |
---|
405 | @author Egtra |
---|
406 | @date 2007/10/22 |
---|
407 | */ |
---|
408 | Dim TraitsIntegerO As IntegerConvertTraits |
---|
409 | With TraitsIntegerO |
---|
410 | .Convert = AddressOf(IntegerO_Convert) |
---|
411 | .Prefix = AddressOf(IntegerO_Prefix) |
---|
412 | .MaxSize = MaxSizeO |
---|
413 | End With |
---|
414 | |
---|
415 | /*! |
---|
416 | @author Egtra |
---|
417 | @date 2007/10/26 |
---|
418 | */ |
---|
419 | Dim TraitsIntegerLO As IntegerConvertTraits |
---|
420 | With TraitsIntegerLO |
---|
421 | .Convert = AddressOf(IntegerLO_Convert) |
---|
422 | .Prefix = AddressOf(IntegerO_Prefix) |
---|
423 | .MaxSize = MaxSizeLO |
---|
424 | End With |
---|
425 | |
---|
426 | /*! |
---|
427 | @brief 符号無し整数をprintfの%o(八進法表現)相当の変換で文字列化する関数。 |
---|
428 | @author Egtra |
---|
429 | @date 2007/10/19 |
---|
430 | @param[in] x 文字列化する整数値。 |
---|
431 | @param[in] d 精度、最小限表示される桁数。DWORD_MAXのとき、指定なしとして、既定値1となる。 |
---|
432 | @param[in] field フィールド幅。 |
---|
433 | @param[in] flags 書式フラグ。 |
---|
434 | @return xの文字列表現 |
---|
435 | */ |
---|
436 | Function FormatIntegerO(x As DWord, d As DWord, field As DWord, flags As FormatFlags) As String |
---|
437 | Return FormatIntegerEx(TraitsIntegerO, x, d, field, flags) |
---|
438 | End Function |
---|
439 | |
---|
440 | /*! |
---|
441 | @brief FormatIntegerOのQWord版。 |
---|
442 | @author Egtra |
---|
443 | @date 2007/10/26 |
---|
444 | */ |
---|
445 | Function FormatIntegerLO(x As QWord, d As DWord, field As DWord, flags As FormatFlags) As String |
---|
446 | Return FormatIntegerEx(TraitsIntegerLO, x, d, field, flags) |
---|
447 | End Function |
---|
448 | |
---|
449 | /*! |
---|
450 | @author Egtra |
---|
451 | @date 2007/10/22 |
---|
452 | */ |
---|
453 | Function IntegerO_Convert(buf As *StrChar, xq As QWord, flags As FormatFlags) As DWord |
---|
454 | Dim x = xq As DWord |
---|
455 | Dim i = MaxSizeO |
---|
456 | While x <> 0 |
---|
457 | buf[i] = ((x And &o7) + &h30) As StrChar |
---|
458 | x >>= 3 |
---|
459 | i-- |
---|
460 | Wend |
---|
461 | If flags And Alt Then |
---|
462 | buf[i] = &h30 |
---|
463 | i-- |
---|
464 | End If |
---|
465 | Return i |
---|
466 | End Function |
---|
467 | |
---|
468 | /*! |
---|
469 | @brief IntegerO_ConvertのQWord版。 |
---|
470 | @author Egtra |
---|
471 | @date 2007/10/26 |
---|
472 | */ |
---|
473 | Function IntegerLO_Convert(buf As *StrChar, x As QWord, flags As FormatFlags) As DWord |
---|
474 | Dim i = MaxSizeLO |
---|
475 | While x <> 0 |
---|
476 | buf[i] = ((x And &o7) + &h30) As StrChar |
---|
477 | x >>= 3 |
---|
478 | i-- |
---|
479 | Wend |
---|
480 | If flags And Alt Then |
---|
481 | buf[i] = &h30 |
---|
482 | i-- |
---|
483 | End If |
---|
484 | Return i |
---|
485 | End Function |
---|
486 | |
---|
487 | /*! |
---|
488 | @author Egtra |
---|
489 | @date 2007/10/22 |
---|
490 | @note #フラグ (Alt)の処理は、IntegerO/LO_Convert内で行うので、ここで処理することはない。 |
---|
491 | */ |
---|
492 | Function IntegerO_Prefix(x As QWord, flags As FormatFlags) As String |
---|
493 | End Function |
---|
494 | |
---|
495 | /*! |
---|
496 | @brief DWordの最大値の十六進法表現ffffffffの文字数 - 1。FormatIntegerO内で使用。 |
---|
497 | @author Egtra |
---|
498 | @date 2007/10/24 |
---|
499 | */ |
---|
500 | Const MaxSizeX = 7 |
---|
501 | |
---|
502 | /*! |
---|
503 | @brief QWordの最大値の十六進法表現ffffffffffffffffの文字数 - 1。FormatIntegerO内で使用。 |
---|
504 | @author Egtra |
---|
505 | @date 2007/10/26 |
---|
506 | */ |
---|
507 | Const MaxSizeLX = 15 |
---|
508 | |
---|
509 | /*! |
---|
510 | @author Egtra |
---|
511 | @date 2007/10/24 |
---|
512 | */ |
---|
513 | Dim TraitsIntegerX As IntegerConvertTraits |
---|
514 | With TraitsIntegerX |
---|
515 | .Convert = AddressOf(IntegerX_Convert) |
---|
516 | .Prefix = AddressOf(IntegerX_Prefix) |
---|
517 | .MaxSize = MaxSizeX |
---|
518 | End With |
---|
519 | |
---|
520 | /*! |
---|
521 | @author Egtra |
---|
522 | @date 2007/10/26 |
---|
523 | */ |
---|
524 | Dim TraitsIntegerLX As IntegerConvertTraits |
---|
525 | With TraitsIntegerLX |
---|
526 | .Convert = AddressOf(IntegerLX_Convert) |
---|
527 | .Prefix = AddressOf(IntegerX_Prefix) |
---|
528 | .MaxSize = MaxSizeLX |
---|
529 | End With |
---|
530 | |
---|
531 | /*! |
---|
532 | @brief 整数をprintfの%x, %X(十六進法)相当の変換で文字列化する関数。 |
---|
533 | @author Egtra |
---|
534 | @date 2007/10/19 |
---|
535 | @param[in] x 文字列化する整数値。 |
---|
536 | @param[in] d 精度、最小限表示される桁数。DWORD_MAXのとき、指定なしとして、既定値1となる。 |
---|
537 | @param[in] field フィールド幅。 |
---|
538 | @param[in] flags 書式フラグ。 |
---|
539 | @return xの文字列表現 |
---|
540 | */ |
---|
541 | Function FormatIntegerX(x As DWord, d As DWord, field As DWord, flags As FormatFlags) As String |
---|
542 | Return FormatIntegerEx(TraitsIntegerX, x, d, field, flags) |
---|
543 | End Function |
---|
544 | |
---|
545 | /*! |
---|
546 | @brief FormatIntegerXのQWord版。 |
---|
547 | @author Egtra |
---|
548 | @date 2007/10/22 |
---|
549 | */ |
---|
550 | Function FormatIntegerLX(x As QWord, d As DWord, field As DWord, flags As FormatFlags) As String |
---|
551 | Return FormatIntegerEx(TraitsIntegerLX, x, d, field, flags) |
---|
552 | End Function |
---|
553 | |
---|
554 | /*! |
---|
555 | @author Egtra |
---|
556 | @date 2007/10/22 |
---|
557 | */ |
---|
558 | Function IntegerX_Convert(buf As *StrChar, xq As QWord, flags As FormatFlags) As DWord |
---|
559 | Dim i = MaxSizeX |
---|
560 | Dim x = xq As DWord |
---|
561 | While x <> 0 |
---|
562 | buf[i] = _System_HexadecimalTable[x And &h0f] |
---|
563 | x >>= 4 |
---|
564 | i-- |
---|
565 | Wend |
---|
566 | Return i |
---|
567 | End Function |
---|
568 | |
---|
569 | /*! |
---|
570 | @brief IntegerX_ConvertのQWord版。 |
---|
571 | @author Egtra |
---|
572 | @date 2007/10/22 |
---|
573 | */ |
---|
574 | Function IntegerLX_Convert(buf As *StrChar, x As QWord, flags As FormatFlags) As DWord |
---|
575 | Dim i = MaxSizeLX |
---|
576 | While x <> 0 |
---|
577 | buf[i] = _System_HexadecimalTable[x And &h0f] |
---|
578 | x >>= 4 |
---|
579 | i-- |
---|
580 | Wend |
---|
581 | Return i |
---|
582 | End Function |
---|
583 | |
---|
584 | /*! |
---|
585 | @author Egtra |
---|
586 | @date 2007/10/24 |
---|
587 | */ |
---|
588 | Function IntegerX_Prefix(x As QWord, flags As FormatFlags) As String |
---|
589 | If flags And Alt Then |
---|
590 | If x <> 0 Then |
---|
591 | IntegerX_Prefix = "0X" |
---|
592 | End If |
---|
593 | End If |
---|
594 | End Function |
---|
595 | |
---|
596 | /*! |
---|
597 | @brief FormatIntegerExへ渡す変換特性を表す構造体型。 |
---|
598 | @author Egtra |
---|
599 | @date 2007/10/22 |
---|
600 | */ |
---|
601 | Type IntegerConvertTraits |
---|
602 | '!変換を行う関数へのポインタ。 |
---|
603 | Convert As *Function(buf As *StrChar, x As QWord, flags As FormatFlags) As DWord |
---|
604 | '!接頭辞を取得する関数へのポインタ。 |
---|
605 | Prefix As *Function(x As QWord, flags As FormatFlags) As String |
---|
606 | '!必要なバッファの大きさ。 |
---|
607 | MaxSize As DWord |
---|
608 | End Type |
---|
609 | |
---|
610 | /*! |
---|
611 | @brief 整数変換全てを行う関数。これを雛形とし、形式毎の差異はIntegerConvertTraitsで表現する。 |
---|
612 | @author Egtra |
---|
613 | @date 2007/10/22 |
---|
614 | @param[in] tr 特性情報。 |
---|
615 | @param[in] x 変換元の数値。 |
---|
616 | @param[in] d 精度。ここでは最低限出力する桁数。 |
---|
617 | @param[in] field フィールド幅。 |
---|
618 | @param[in] flags フラグ。 |
---|
619 | */ |
---|
620 | Function FormatIntegerEx(ByRef tr As IntegerConvertTraits, x As QWord, d As DWord, field As DWord, flags As FormatFlags) As String |
---|
621 | If d = DWORD_MAX Then |
---|
622 | d = 1 |
---|
623 | Else |
---|
624 | '精度が指定されているとき、ゼロフラグは無視される。 |
---|
625 | '仕様上、左揃えのときも無視されるが、それはAdjustFieldWidthが行ってくれる。 |
---|
626 | flags And= Not Zero |
---|
627 | End If |
---|
628 | |
---|
629 | Dim sb = New System.Text.StringBuilder |
---|
630 | With sb |
---|
631 | Dim prefixFunc = tr.Prefix |
---|
632 | Dim prefix = prefixFunc(x, flags) |
---|
633 | sb.Append(prefix) |
---|
634 | |
---|
635 | Dim prefixLen = 0 As DWord |
---|
636 | If String.IsNullOrEmpty(prefix) = False Then |
---|
637 | prefixLen = prefix.Length As DWord |
---|
638 | End If |
---|
639 | |
---|
640 | Dim buf = GC_malloc_atomic((tr.MaxSize + 1) * SizeOf (StrChar)) As *StrChar |
---|
641 | Dim convertFunc = tr.Convert |
---|
642 | Dim bufStartPos = convertFunc(buf, x, flags) |
---|
643 | |
---|
644 | Dim len = (tr.MaxSize - bufStartPos) As Long |
---|
645 | If len < 0 Then |
---|
646 | Debug |
---|
647 | End If |
---|
648 | If len < d Then |
---|
649 | .Append(&h30 As StrChar, d - len) |
---|
650 | End If |
---|
651 | |
---|
652 | .Append(buf, bufStartPos + 1, len) |
---|
653 | |
---|
654 | AdjustFieldWidth(sb, field, flags And (Not (Sign Or Blank)), prefixLen) |
---|
655 | End With |
---|
656 | FormatIntegerEx = sb.ToString() |
---|
657 | |
---|
658 | If (flags And Cap) = 0 Then |
---|
659 | FormatIntegerEx = FormatIntegerEx.ToLower() |
---|
660 | End If |
---|
661 | End Function |
---|
662 | |
---|
663 | /*! |
---|
664 | @brief QWordの最大値18446744073709551615の文字数 - 1。FormatIntegerLU内で使用。 |
---|
665 | @author Egtra |
---|
666 | @date 2007/09/18 |
---|
667 | */ |
---|
668 | Const MaxSizeLU = 19 |
---|
669 | |
---|
670 | /*! |
---|
671 | @brief 文字列をフィールド幅まで満たされるように空白などを挿入する。 |
---|
672 | @author Egtra |
---|
673 | @date 2007/10/13 |
---|
674 | @param[in,out] sb 対象文字列 |
---|
675 | @param[in] field フィールド幅 |
---|
676 | @param[in] hasSign 符号を持っている(負の値か)か否か |
---|
677 | @param[in] flags フラグ |
---|
678 | @param[in] prefixLen (あれば)接頭辞の文字数。ゼロ埋めする際、この数だけ挿入位置を後ろにする。 |
---|
679 | sbが"-1"のように負符号を持っている場合は、呼出元でSignフラグ(またはBlank)を立てること。 |
---|
680 | */ |
---|
681 | Sub AdjustFieldWidth(sb As System.Text.StringBuilder, field As DWord, flags As FormatFlags, prefixLen = 0 As DWord) |
---|
682 | With sb |
---|
683 | If .Length < field Then |
---|
684 | Dim embeddedSize = field - .Length |
---|
685 | If flags And Left Then |
---|
686 | .Append(&h20, embeddedSize) |
---|
687 | Else |
---|
688 | Dim insPos As Long |
---|
689 | If (flags And Zero) <> 0 Then |
---|
690 | If (flags And Blank) Or (flags And Sign) Then |
---|
691 | insPos++ |
---|
692 | End If |
---|
693 | insPos += prefixLen |
---|
694 | .Insert(insPos, String$(embeddedSize, "0")) |
---|
695 | Else |
---|
696 | .Insert(insPos, String$(embeddedSize, " ")) |
---|
697 | End If |
---|
698 | End If |
---|
699 | End If |
---|
700 | End With |
---|
701 | End Sub |
---|
702 | |
---|
703 | End Namespace 'Detail |
---|
704 | |
---|
705 | End Namespace 'Strings |
---|
706 | End Namespace 'ActiveBasic |
---|