source: trunk/Include/Classes/ActiveBasic/Strings/SPrintF.ab@ 359

Last change on this file since 359 was 359, checked in by dai, 17 years ago

メソッドの実装がある場合(抽象メソッドでない場合)にのみ "override" 修飾子を必要とする仕様へと変更。
インターフェイス実装時に基底クラスのメソッドの再実装を可能にした。
デバッガのステップイン、ステップアウトのショートカットキーを交換

File size: 9.9 KB
RevLine 
[335]1'Classes/ActiveBasic/Strings/SPrintF.ab
2
3Namespace ActiveBasic
4Namespace Strings
5
6Namespace 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
18xに無限大、無限小、非数を渡した場合の動作は未定義。
19*/
20Function 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
42 sign = False
43 End If
44
45 '1e16 <= x < 1e17へ正規化
46 '(元のx) = (正規化後のx) ^ (d - 17)である。
47 Dim d = Math.Floor(Math.Log10(x)) As Long
48 If d < 16 Then
49 x *= ipow(10, +17 - d)
50 ElseIf d > 16 Then
51 x /= ipow(10, -17 + d)
52 End If
53
54 '補正
55 While x < 1e16
56 x *= 10
57 d--
58 Wend
59 While x >= 1e17
60 x /= 10
61 d++
62 Wend
63
64 d--
65 e = d
66
67 FloatToChars = Str$(x As QWord)
68End Function
69
70/*!
71@brief 書式化関数群で使用するフラグ。
72@author Egtra
73@date 2007/09/18
74*/
75Const Enum FormatFlags
76 '! 何も指定がない。
77 None = &h0
78 '! 符号、+。符号付変換[diAaEeFfGg]のとき、正の値でも符号を付ける。
79 Sign = &h1
80 /*! 空白、空白文字。
81 符号付変換[diAaEeFfGg]のとき、正の値ならば符号分の空白を開ける。Signが立っているときには無視される。
82 */
83 Blank = &h2
84 /*! ゼロ、0。
85 [diouXxAaEeFfGg]で、フィールドの空きを0で埋める。leftが立っているときには無視される。
86 */
87 Zero = &h4
88 '! 左揃え、-。フィールド内で左揃えにする。
89 Left = &h8
90 /*! 代替表記、#。
91 <ul>
[358]92 <li>[OoXx]では、値が0でない場合、先頭に0、0xを付ける。</ul>
[335]93 <li>[AaEeFfGg]では、精度0でも小数点を付ける。</ul>
94 <li>[Gg]では、それに加え、小数部末尾の0の省略を行わないようにする。</ul>
95 </ul>
96 */
97 Alt = &h10
98 '! 大文字。使用するアルファベットを大文字にする。[aefgx]を[AEFGX]化する。
99 Cap = &h20
100End Enum
101
102/*!
103@brief 浮動小数点数をprintfの%e, %E相当の変換で文字列化する関数。
104@author Egtra
105@date 2007/09/18
106@param[in] x 文字列化する浮動小数点数値。
107@param[in] d 精度。小数点以下の桁数。DWORD_MAXのとき、指定なしとして既定値6となる。
108@param[in] field フィールド幅。
109@param[in] flags 書式フラグ。
110@return xの文字列表現
111
112@todo 末尾桁四捨五入
113*/
114Function FormatFloatE(x As Double, d As DWord, field As DWord, flags As FormatFlags) As String
115 Dim sb = New System.Text.StringBuilder
116 With sb
117 If d = DWORD_MAX Then
118 d = 6
119 End If
120
[355]121 Dim e As Long, negative As Boolean
122 Dim s = FloatToChars(x, e, negative)
[335]123
[355]124 If negative Then
[335]125 .Append("-")
126 Else
127 If flags And Sign Then
128 .Append("+")
129 ElseIf flags And Blank Then
130 .Append(" ")
131 End If
132 End If
133
134 .Append(s[0])
135
136 If (flags And Alt) Or d > 0 Then
137 .Append(".")
138 Dim outputLen = s.Length - 1
139 If outputLen >= d Then
140 .Append(s, 1, d)
141 Else 'sで用意された桁が指定された精度より少ないとき
142 .Append(s, 1, outputLen)
143 .Append(&h30 As StrChar, d - outputLen) '足りない桁は0埋め
144 End If
145 End If
146
147 If flags And Cap Then
148 .Append("E")
149 Else
150 .Append("e")
151 End If
152
[355]153 .Append(FormatIntegerD(e, 2, 0, Sign Or Zero))
[335]154
[355]155 AdjustFieldWidth(sb, field, negative, flags)
[335]156 End With
157 FormatFloatE = sb.ToString()
158End Function
159
160'! DWordの最大値4294967295の文字数 - 1。FormatIntegerU内で使用。
[355]161Const MaxSizeU = 9
[335]162
163/*!
164@brief 符号無し整数をprintfの%u相当の変換で文字列化する関数。
165@author Egtra
166@date 2007/09/18
167@param[in] x 文字列化する整数値。
168@param[in] d 精度、最小限表示される桁数。DWORD_MAXのとき、指定なしとして、既定値1となる。
169@param[in] field フィールド幅。
170@param[in] flags 書式フラグ。
171@return xの文字列表現
172*/
173Function FormatIntegerU(x As DWord, d As DWord, field As DWord, flags As FormatFlags) As String
[358]174 FormatIntegerU = FormatInteger(x, d, field, flags And (Not (Sign Or Blank)), 0)
[355]175End Function
[335]176
[358]177/*!
178DWordの最大値4294967295やLongの最大値2147483647、最小値-2147483648
179(全て十進法)の符号部を除いた文字数 - 1。FormatIntegerU内で使用。
180*/
[355]181Const MaxSizeD = 9
182
183/*!
184@brief 符号有り整数をprintfの%u相当の変換で文字列化する関数。
185@author Egtra
186@date 2007/10/13
187@param[in] x 文字列化する整数値。
188@param[in] d 精度、最小限表示される桁数。DWORD_MAXのとき、指定なしとして、既定値1となる。
189@param[in] field フィールド幅。
190@param[in] flags 書式フラグ。
191@return xの文字列表現
192*/
193Function FormatIntegerD(x As Long, d As DWord, field As DWord, flags As FormatFlags) As String
194 Dim dwX As DWord
195
196 Dim signChar As StrChar
197 If x < 0 Then
198 dwX = (-x) As DWord
199 signChar = Asc("-")
200 Else
201 dwX = x As DWord
202 If flags And Sign Then
203 signChar = Asc("+")
204 ElseIf flags And Blank Then
205 signChar = Asc(" ")
206 End If
207 End If
208
209 FormatIntegerD = FormatInteger(dwX, d, field, flags, signChar)
210End Function
211
212/*!
213@brief 整数をprintfの%d, %u相当の変換で文字列化する関数。
214@author Egtra
215@date 2007/09/18
216@param[in] x 文字列化する整数値。
217@param[in] d 精度、最小限表示される桁数。DWORD_MAXのとき、指定なしとして、既定値1となる。
218@param[in] field フィールド幅。
219@param[in] flags 書式フラグ。
220@param[in] signChar 符号部分の文字。\0なら存在しないとして扱われる。
221@return xの文字列表現
222*/
223Function FormatInteger(x As DWord, d As DWord, field As DWord, flags As FormatFlags, signChar As StrChar) As String
[358]224 PreProcessFormatInteger(d, flags)
[335]225
226 Dim sb = New System.Text.StringBuilder
227 With sb
[355]228 If signChar <> 0 Then
229 .Append(signChar)
230 End If
231
232 Dim buf[MaxSizeU] As StrChar
233 Dim i = MaxSizeU
[335]234 While x <> 0
235 buf[i] = (x As Int64 Mod 10 + &h30) As StrChar 'Int64への型変換は#117対策
236 x \= 10
237 i--
238 Wend
239
[355]240 Dim len = (MaxSizeU - i) As Long
[335]241 If len < d Then
242 .Append(&h30 As StrChar, d - len)
243 End If
244
245 .Append(buf, i + 1, len)
246
[358]247 AdjustFieldWidth(sb, field, signChar <> 0, flags)
[355]248 End With
249 FormatInteger = sb.ToString()
250End Function
251
[358]252
253/*!
254DWordの最大値の八進法表現37777777777の文字数 - 1。FormatIntegerO内で使用。
255*/
256Const MaxSizeO = 10
257
258/*!
259@brief 整数をprintfの%o相当の変換で文字列化する関数。
260@author Egtra
261@date 2007/10/19
262@param[in] x 文字列化する整数値。
263@param[in] d 精度、最小限表示される桁数。DWORD_MAXのとき、指定なしとして、既定値1となる。
264@param[in] field フィールド幅。
265@param[in] flags 書式フラグ。
266@return xの文字列表現
267*/
268Function FormatIntegerO(x As DWord, d As DWord, field As DWord, flags As FormatFlags) As String
269 PreProcessFormatInteger(d, flags)
270
271 Dim sb = New System.Text.StringBuilder
272 With sb
273 Dim buf[MaxSizeO] As StrChar
274 Dim i = MaxSizeO
275 While x <> 0
276 buf[i] = ((x And &o7) + &h30) As StrChar
277 x >>= 3
278 i--
279 Wend
280
281 Dim len = (MaxSizeO - i) As Long
282
283 If flags And Alt Then
284 .Append(&h30 As StrChar)
285 len++
286 End If
287
288 If len < d Then
289 .Append(&h30 As StrChar, d - len)
290 End If
291
292 .Append(buf, i + 1, len)
293
294 AdjustFieldWidth(sb, field, False, flags And (Not (Sign Or Blank)))
295 End With
296 FormatIntegerO = sb.ToString()
297End Function
298
299/*!
300DWordの最大値の十六進法表現ffffffffの文字数 - 1。FormatIntegerO内で使用。
301*/
302Const MaxSizeX = 7
303
304/*!
305@brief 整数をprintfの%x, %X相当の変換で文字列化する関数。
306@author Egtra
307@date 2007/10/19
308@param[in] x 文字列化する整数値。
309@param[in] d 精度、最小限表示される桁数。DWORD_MAXのとき、指定なしとして、既定値1となる。
310@param[in] field フィールド幅。
311@param[in] flags 書式フラグ。
312@return xの文字列表現
313*/
314Function FormatIntegerX(x As DWord, d As DWord, field As DWord, flags As FormatFlags) As String
315 PreProcessFormatInteger(d, flags)
316
317 Dim sb = New System.Text.StringBuilder
318 With sb
319 Dim prefixLen = 0 As DWord
320 If (flags And Alt) Then
321 If x <> 0 Then
322 .Append("0X")
323 prefixLen = 2
324 End If
325 End If
326
327 Dim buf[MaxSizeX] As StrChar
328 Dim i = MaxSizeX
329 While x <> 0
330 buf[i] = _System_HexadecimalTable[x And &h0f]
331 x >>= 4
332 i--
333 Wend
334
335 Dim len = (MaxSizeX - i) As Long
336
337 If len < d Then
338 .Append(&h30 As StrChar, d - len)
339 End If
340
341 .Append(buf, i + 1, len)
342
343 AdjustFieldWidth(sb, field, False, flags And (Not (Sign Or Blank)), prefixLen)
344 End With
345 FormatIntegerX = sb.ToString()
346
347 If (flags And Cap) = 0 Then
348 FormatIntegerX = FormatIntegerX.ToLower()
349 End If
350End Function
351
[355]352'! QWordの最大値18446744073709551615の文字数 - 1。FormatIntegerLU内で使用。
353Const MaxSizeLU = 19
354
355/*!
[358]356@brief 整数変換共通の前処理
357@author Egtra
358@date 2007/10/19
359@param[in, out] d 精度。DWORD_MAXで省略とみなされ、精度1になる。
360@param[in, out] flags フラグ。精度が指定されたとき、Zeroを消す。
361*/
362Sub PreProcessFormatInteger(ByRef d As DWord, ByRef flags As FormatFlags)
363 If d = DWORD_MAX Then
364 d = 1
365 Else
366 '精度が指定されているとき、ゼロフラグは無視される。
367 '左揃えのときも無視されるが、それはAdjustFieldWidthが行ってくれる。
368 flags And= Not Zero
369 End If
370End Sub
371
372/*!
[355]373@brief 文字列をフィールド幅まで満たされるように空白などを挿入する。
[358]374@param [in,out] sb 対象文字列
375@param [in] field フィールド幅
376@param [in] hasSign 符号を持っている(負の値か)か否か
377@param [in] flags フラグ
378@param [in] prefixLen (あれば)接頭辞の文字数。ゼロ埋めする際、この数だけ挿入位置を後ろにする。
[355]379*/
[358]380Sub AdjustFieldWidth(sb As System.Text.StringBuilder, field As DWord, hasSign As Boolean, flags As FormatFlags, prefixLen = 0 As DWord)
[355]381 With sb
382 If .Length < field Then
383 Dim embeddedSize = field - .Length
[335]384 If flags And Left Then
385 .Append(&h20, embeddedSize)
386 Else
[355]387 Dim insPos As Long
388 If (flags And Zero) <> 0 Then
389 If ((flags And Blank) Or (flags And Sign) Or hasSign) Then
390 insPos++
391 End If
[358]392 insPos += prefixLen
[355]393 .Insert(insPos, String$(embeddedSize, "0"))
394 Else
395 .Insert(insPos, String$(embeddedSize, " "))
396 End If
[335]397 End If
398 End If
399 End With
[355]400End Sub
[335]401
402End Namespace 'Detail
403
404End Namespace 'Strings
405End Namespace 'ActiveBasic
Note: See TracBrowser for help on using the repository browser.