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

Last change on this file since 358 was 358, checked in by イグトランス (egtra), 17 years ago

FormatIntegerO, FormatIntegerXを実装

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 Debug
321 If (flags And Alt) Then
322 If x <> 0 Then
323 .Append("0X")
324 prefixLen = 2
325 End If
326 End If
327
328 Dim buf[MaxSizeX] As StrChar
329 Dim i = MaxSizeX
330 While x <> 0
331 buf[i] = _System_HexadecimalTable[x And &h0f]
332 x >>= 4
333 i--
334 Wend
335
336 Dim len = (MaxSizeX - i) As Long
337
338 If len < d Then
339 .Append(&h30 As StrChar, d - len)
340 End If
341
342 .Append(buf, i + 1, len)
343
344 AdjustFieldWidth(sb, field, False, flags And (Not (Sign Or Blank)), prefixLen)
345 End With
346 FormatIntegerX = sb.ToString()
347
348 If (flags And Cap) = 0 Then
349 FormatIntegerX = FormatIntegerX.ToLower()
350 End If
351End Function
352
353'! QWordの最大値18446744073709551615の文字数 - 1。FormatIntegerLU内で使用。
354Const MaxSizeLU = 19
355
356/*!
357@brief 整数変換共通の前処理
358@author Egtra
359@date 2007/10/19
360@param[in, out] d 精度。DWORD_MAXで省略とみなされ、精度1になる。
361@param[in, out] flags フラグ。精度が指定されたとき、Zeroを消す。
362*/
363Sub PreProcessFormatInteger(ByRef d As DWord, ByRef flags As FormatFlags)
364 If d = DWORD_MAX Then
365 d = 1
366 Else
367 '精度が指定されているとき、ゼロフラグは無視される。
368 '左揃えのときも無視されるが、それはAdjustFieldWidthが行ってくれる。
369 flags And= Not Zero
370 End If
371End Sub
372
373/*!
374@brief 文字列をフィールド幅まで満たされるように空白などを挿入する。
375@param [in,out] sb 対象文字列
376@param [in] field フィールド幅
377@param [in] hasSign 符号を持っている(負の値か)か否か
378@param [in] flags フラグ
379@param [in] prefixLen (あれば)接頭辞の文字数。ゼロ埋めする際、この数だけ挿入位置を後ろにする。
380*/
381Sub AdjustFieldWidth(sb As System.Text.StringBuilder, field As DWord, hasSign As Boolean, flags As FormatFlags, prefixLen = 0 As DWord)
382 With sb
383 If .Length < field Then
384 Dim embeddedSize = field - .Length
385 If flags And Left Then
386 .Append(&h20, embeddedSize)
387 Else
388 Dim insPos As Long
389 If (flags And Zero) <> 0 Then
390 If ((flags And Blank) Or (flags And Sign) Or hasSign) Then
391 insPos++
392 End If
393 insPos += prefixLen
394 .Insert(insPos, String$(embeddedSize, "0"))
395 Else
396 .Insert(insPos, String$(embeddedSize, " "))
397 End If
398 End If
399 End If
400 End With
401End Sub
402
403End Namespace 'Detail
404
405End Namespace 'Strings
406End Namespace 'ActiveBasic
Note: See TracBrowser for help on using the repository browser.