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
Line 
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>
92 <li>[OoXx]では、値が0でない場合、先頭に0、0xを付ける。</ul>
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
121 Dim e As Long, negative As Boolean
122 Dim s = FloatToChars(x, e, negative)
123
124 If negative Then
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
153 .Append(FormatIntegerD(e, 2, 0, Sign Or Zero))
154
155 AdjustFieldWidth(sb, field, negative, flags)
156 End With
157 FormatFloatE = sb.ToString()
158End Function
159
160'! DWordの最大値4294967295の文字数 - 1。FormatIntegerU内で使用。
161Const MaxSizeU = 9
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
174 FormatIntegerU = FormatInteger(x, d, field, flags And (Not (Sign Or Blank)), 0)
175End Function
176
177/*!
178DWordの最大値4294967295やLongの最大値2147483647、最小値-2147483648
179(全て十進法)の符号部を除いた文字数 - 1。FormatIntegerU内で使用。
180*/
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
224 PreProcessFormatInteger(d, flags)
225
226 Dim sb = New System.Text.StringBuilder
227 With sb
228 If signChar <> 0 Then
229 .Append(signChar)
230 End If
231
232 Dim buf[MaxSizeU] As StrChar
233 Dim i = MaxSizeU
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
240 Dim len = (MaxSizeU - i) As Long
241 If len < d Then
242 .Append(&h30 As StrChar, d - len)
243 End If
244
245 .Append(buf, i + 1, len)
246
247 AdjustFieldWidth(sb, field, signChar <> 0, flags)
248 End With
249 FormatInteger = sb.ToString()
250End Function
251
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
352'! QWordの最大値18446744073709551615の文字数 - 1。FormatIntegerLU内で使用。
353Const MaxSizeLU = 19
354
355/*!
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/*!
373@brief 文字列をフィールド幅まで満たされるように空白などを挿入する。
374@param [in,out] sb 対象文字列
375@param [in] field フィールド幅
376@param [in] hasSign 符号を持っている(負の値か)か否か
377@param [in] flags フラグ
378@param [in] prefixLen (あれば)接頭辞の文字数。ゼロ埋めする際、この数だけ挿入位置を後ろにする。
379*/
380Sub AdjustFieldWidth(sb As System.Text.StringBuilder, field As DWord, hasSign As Boolean, flags As FormatFlags, prefixLen = 0 As DWord)
381 With sb
382 If .Length < field Then
383 Dim embeddedSize = field - .Length
384 If flags And Left Then
385 .Append(&h20, embeddedSize)
386 Else
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
392 insPos += prefixLen
393 .Insert(insPos, String$(embeddedSize, "0"))
394 Else
395 .Insert(insPos, String$(embeddedSize, " "))
396 End If
397 End If
398 End If
399 End With
400End Sub
401
402End Namespace 'Detail
403
404End Namespace 'Strings
405End Namespace 'ActiveBasic
Note: See TracBrowser for help on using the repository browser.