-
Notifications
You must be signed in to change notification settings - Fork 11
Expand file tree
/
Copy pathstring.PRG
More file actions
454 lines (406 loc) · 14.3 KB
/
string.PRG
File metadata and controls
454 lines (406 loc) · 14.3 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
DEFINE CLASS String AS StaticVariable OF Static.prg
#DEFINE StringSplitOptions_IncludeLastElement 2
#DEFINE StringSplitOptions_RemoveEmptyOptions 4
#DEFINE StringSplitOptions_CaseInsensitive 8
#DEFINE StringSplitOptions_IncludeParseChar 16
#DEFINE StringCompareOptions_CaseInsensitive 1
#DEFINE StringCompareOptions_Exact 2
cShortDatePattern = 'MM/dd/yyyy'
cShortTimePattern = "hh:mm tt"
cLongTimePattern = "hh:mm:ss tt"
cCurrencySymbol = SET("currency", 1)
cNumberSeperator = SET("separator")
cDecimalPoint = SET("point")
PROTECTED FUNCTION getComparisonFlags
LPARAMETERS nFlags, lCaseSensitive, lExact
lCaseSensitive = BITTEST(nFlags,0)
lExact = BITTEST(nFlags,1)
************************************************************
FUNCTION Format
************************************************************
* Mimics the String.Format() Method of NET
************************************************************
LPARAMETERS cString, vPara0, vPara1, vPara2, vPara3, vPara4, vPara5, vPara6, vPara7, vPara8, vPara9
LOCAL nCount, cCount, cReturn, cSearch, cFormat
cReturn = cString
FOR nCount = 1 TO OCCURS("{", cString)
cSearch = This.Extract(cString, "{", "}", nCount, 4)
cFormat = This.Extract(cSearch, ":", "}")
cCount = CHRTRAN(STRTRAN(cSearch, cFormat,""), "{:}","")
IF TRANSFORM(VAL(cCount))!= cCount && A lone { for example
LOOP
ENDIF
IF EMPTY(cFormat)
cReturn = STRTRAN(cReturn, cSearch, TRANSFORM(EVALUATE("vPara"+cCount)) )
ELSE
xParam = EVALUATE("vPara"+cCount)
DO CASE
CASE INLIST(VARTYPE(xParam),'D','T')
cReturn = STRTRAN(cReturn, cSearch, This.DateFormat(xParam, cFormat))
CASE INLIST(VARTYPE(xParam),'N','Y')
cReturn = STRTRAN(cReturn, cSearch, This.NumericFormat(xParam, cFormat))
OTHERWISE
cReturn = STRTRAN(cReturn, cSearch, TRANSFORM(xParam,cFormat) )
ENDCASE
ENDIF
ENDFOR
cReturn = STRTRAN(cReturn, "\n", CHR(10)+CHR(13))
RETURN cReturn
PROTECTED FUNCTION DateFormat
LPARAMETERS dtConvert, cFormat
LOCAL cDate, cCentury, dConvert, cResult
cResult = ""
*-- [Matt Slay: 2017-01-22]--
If IsNull(dtConvert)
Return ""
Endif
IF VARTYPE(dtConvert)="D"
dConvert = dtConvert
dtConvert = DTOT(dConvert)
ELSE
dConvert = TTOD(dtConvert)
ENDIF
IF LEN(cFormat)=1
IF INLIST(cFormat, 'r', 'u', 'U')
* Adjust time to GMT
DECLARE INTEGER GetTimeZoneInformation IN kernel32 STRING @lpTimeZoneInformation
LOCAL cTimeZone, iBiasSeconds
cTimeZone = REPL(Chr(0), 172)
GetTimeZoneInformation(@cTimeZone)
iBiasSeconds = 60 * INT( ASC(SUBSTR(cTimeZone, 1,1)) + ;
BitLShift(ASC(SUBSTR(cTimeZone, 2,1)), 8) +;
BitLShift(ASC(SUBSTR(cTimeZone, 3,1)), 16) +;
BitLShift(ASC(SUBSTR(cTimeZone, 4,1)), 24))
dtConvert = dtConvert + iBiasSeconds
dConvert = TTOD(dtConvert)
ENDIF
DO CASE
CASE cFormat='d' && Short date 10/12/2002
cResult=TRANSFORM(dConvert, "@YS")
CASE cFormat='D' && Long date Saturday, October 28, 2017. Can't use @YL
cFormat='D, MMMM dd, yyyy'
CASE cFormat='f' && Full date & time December 10, 2002 10:11 PM
cFormat='MMMM dd, yyyy hh:mm tt'
CASE cFormat='F' && Full date & time (long) December 10, 2002 10:11:29 PM
cFormat='MMMM dd, yyyy hh:mm:ss tt'
CASE cFormat='g' && Global Default date & time 10/12/2002 10:11 PM
cFormat= This.cShortDatePattern+' '+This.cShortTimePattern
CASE cFormat='G' && Global Default date & time (long) 10/12/2002 10:11:29 PM
cFormat= This.cShortDatePattern +' '+This.cLongTimePattern
CASE cFormat='M' && Month day pattern December 10
cFormat='MMMM dd'
CASE cFormat='r' && RFC1123 date string Tue, 10 Dec 2002 22:11:29 GMT
cFormat='ddd, dd MMM yyyy hh:mm:ss GMT'
CASE cFormat='s' && Sortable date string 2002-12-10T22:11:29
cResult = TTOC(dtConvert,3)
CASE cFormat='t' && Short time 10:11 PM
cFormat=This.cShortTimePattern
CASE cFormat='T' && Long time 10:11:29 PM
cFormat= This.cLongTimePattern
CASE cFormat='u' && Universal sortable, local time 2002-12-10 22:13:50Z
cFormat='yyyy-MM-dd hh:mm:ssZ'
CASE cFormat='U' && Universal sortable, GMT December 11, 2002 3:13:50 AM
cFormat="D, MMMM dd, yyyy hh:mm:ss tt"
CASE cFormat='Y' && Year month pattern December, 2002
cFormat="MMMM, yyyy"
CASE cFormat='y' && Year month pattern December 2002
cFormat="MMMM yyyy"
ENDCASE
ENDIF
IF EMPTY(cResult) AND LEN(cFormat)>1
cResult=This.ParseDateFormat(cFormat, dtConvert)
ENDIF
RETURN cResult
PROTECTED FUNCTION ParseDateFormat
LPARAMETERS cFormat, dtVar
cFormat=STRTRAN(cFormat,"hh", PADL(HOUR(dtVar),2,'0'))
cFormat=STRTRAN(cFormat,"mm", PADL(MINUTE(dtVar),2,'0'))
cFormat=STRTRAN(cFormat,"ss", PADL(SEC(dtVar),2,'0'))
cFormat=STRTRAN(cFormat,"MMMM", CMONTH(dtVar))
cFormat=STRTRAN(cFormat,"MMM", LEFT(CMONTH(dtVar),3))
cFormat=STRTRAN(cFormat,"MM", PADL(MONTH(dtVar),2,'0'))
cFormat=STRTRAN(cFormat,"ddd", LEFT(CDOW(dtVar),3))
cFormat=STRTRAN(cFormat,"dd", PADL(DAY(dtVar),2,'0'))
cFormat=STRTRAN(cFormat,"yyyy", TRANSFORM(YEAR(dtVar)))
cFormat=STRTRAN(cFormat,"yy", RIGHT(TRANSFORM(YEAR(dtVar)),2))
cFormat=STRTRAN(cFormat,"tt", IIF(HOUR(dtVar)<12,"AM","PM"))
cFormat=STRTRAN(cFormat,"D", CDOW(dtVar))
RETURN cFormat
PROTECTED FUNCTION NumericFormat
LPARAMETERS nConvert, cFormatCode
LOCAL cResult, cFormat, iPrecision, cWidth, cPattern, iDecimals
LOCAL cSeparator, cPoint, cSymbol
cResult = ""
cFormat = UPPER(LEFT(cFormatCode,1))
cWidth = SUBSTR(cFormatCode,2)
iPrecision = IIF(EMPTY(cWidth) and cFormatCode='C', 2, VAL(cWidth))
iDecimals = SET("Decimals")
SET DECIMALS TO iPrecision
cSeparator= SET("SEPARATOR")
cPoint = SET("POINT")
cSymbol = SET("CURRENCY",1)
SET CURRENCY TO (This.cCurrencySymbol)
SET POINT TO (This.cDecimalPoint)
SET SEPARATOR TO (This.cNumberSeperator)
DO CASE
CASE cFormat='D' AND nConvert=INT(nConvert) && Decimal
cResult=TRANSFORM(nConvert)
IF NOT EMPTY(cWidth) AND VAL(cWidth) > LEN(cResult)
cResult = This.PadLeft(cResult, VAL(cWidth), '0')
ENDIF
CASE cFormat='E' && Exponential
cPattern = "@^"
cResult=TRANSFORM(nConvert, cPattern)
CASE cFormat = 'C' && Currency
cPattern = "@$ 999,999,999,999"+IIF(iPrecision <=0,'','.'+REPLICATE('9',iPrecision))
cResult = ALLTRIM(TRANSFORM(nConvert, cPattern))
CASE INLIST(cFormat,'F','P','N') && Fixed # of decimal place (default 0)
cPattern = "999,999,999,999"+IIF(iPrecision <=0,'','.'+REPLICATE('9',iPrecision))
IF cFormat='P'
nConvert = nConvert * 100
cPattern = cPattern + '%'
ENDIF
cResult = ALLTRIM(TRANSFORM(nConvert, cPattern))
CASE cFormat='G' && General
cResult=TRANSFORM(nConvert)
CASE cFormat='P' && Percent
iPrecision = IIF(LEN(cFormat)=1,2,iPrecision ) && Default to 2 decimal places
cResult= TRANSFORM(nConvert*100) +'%'
CASE cFormat='R' && Round
cResult=TRANSFORM(nConvert)
CASE cFormat='X' && Hex
cResult=TRANSFORM(nConvert, "@0")
* ES Convert number to string
CASE cFormat = 'W' && Words
cResult = This.NumberToWords(nConvert)
ENDCASE
SET DECIMALS TO (iDecimals)
SET CURRENCY TO (cSymbol)
SET POINT TO (cPoint)
SET SEPARATOR TO (cSeparator)
RETURN cResult
FUNCTION NumberToWords
*********************************************************
** Author : Ramani (Subramanian.G)
** áFoxAcc Software / Winners Software
** www.winnersoft.coolfreepages.com
** Type á: Freeware with reservation to Copyrights
** Warranty : Nothing implied or explicit
** Last modified : June, 2003
*********************************************************
LPARAMETER amt
amt = ABS(amt)
IF amt > 999999999999.99 && => 1000 billion
=MESSAGEBOX("Amount exceeds word convertion provision. Contact system administrator", ;
0+16, "CAUTION. Check total amount !")
ENDIF
IF amt = 0
RETURN "Zero"
ENDIF
LOCAL lcNumPhrase, lcNumStr
PRIVATE lcWord1, lcWord2, lcWord3, lcWord4, lcWord5, lcWord6, lcWord7, ;
lcWord8, lcWord9, lcWord10, lcWord11, lcWord12, lcWord13, lcWord14, ;
lcWord15, lcWord16, lcWord17, lcWord18, lcWord19, lcWord20, lcWord30, ;
lcWord40, lcWord50, lcWord60, lcWord70, lcWord80, lcWord90
lcWord1 = "One "
lcWord2 = "Two "
lcWord3 = "Three "
lcWord4 = "Four "
lcWord5 = "Five "
lcWord6 = "Six "
lcWord7 = "Seven "
lcWord8 = "Eight "
lcWord9 = "Nine "
lcWord10 = "Ten "
lcWord11 = "Eleven "
lcWord12 = "Twelve "
lcWord13 = "Thirteen "
lcWord14 = "Fourteen "
lcWord15 = "Fifteen "
lcWord16 = "Sixteen "
lcWord17 = "Seventeen "
lcWord18 = "Eighteen "
lcWord19 = "Ninteen "
lcWord20 = "Twenty "
lcWord30 = "Thirty "
lcWord40 = "Forty "
lcWord50 = "Fifty "
lcWord60 = "Sixty "
lcWord70 = "Seventy "
lcWord80 = "Eighty "
lcWord90 = "Ninety "
m.lcNumPhrase = ""
m.lcNumStr = STR(amt,17,4)
IF VAL(SUBSTR(m.lcNumStr,1,3)) > 0 && Amount in Billions
m.lcNumPhrase = m.lcNumPhrase + THIS.Numword(SUBSTR(m.lcNumStr,1,3)) + " Billion "
ENDIF
IF VAL(SUBSTR(m.lcNumStr,4,3)) > 0 && Amount in millions
m.lcNumPhrase = m.lcNumPhrase + THIS.Numword(SUBSTR(m.lcNumStr,4,3)) + " Million "
ENDIF
IF VAL(SUBSTR(m.lcNumStr,7,3)) > 0 && Amount in thousands
m.lcNumPhrase = m.lcNumPhrase + THIS.Numword(SUBSTR(m.lcNumStr,7,3)) + " Thousand "
ENDIF
IF VAL(SUBSTR(m.lcNumStr,10,3)) > 0 && Amount below thousands
m.lcNumPhrase = m.lcNumPhrase + THIS.Numword(SUBSTR(m.lcNumStr,10,3))
ENDIF
IF VAL(SUBSTR(m.lcNumStr,14,2)) > 0 && Amount in Decimals
** needs tingering depending on digits - Default is 2 decimals
IF LEN(ALLTRIM(m.lcNumPhrase)) > 1
m.lcNumPhrase = ALLTRIM(m.lcNumPhrase) + " and "
ELSE
m.lcNumPhrase = "Zero and "
ENDIF
m.lcNumPhrase = m.lcNumPhrase + SUBSTR(m.lcNumStr,14,2) + "/100"
ENDIF
RETURN m.lcNumPhrase
*********************************************************
** Called by: numtoword() (function in NUMWORD.PRG)
*********************************************************
PROTECTED FUNCTION Numword
LPARAMETERS tStr
LOCAL lnStr, lcPhrase, lcStr
lcPhrase = " "
lnStr = VAL(tStr)
** Hundredth position
IF lnStr > 99
lcStr = LEFT(tStr,1)
lcPhrase = lcWord&lcStr + "Hundred "
ENDIF
** Balance Position
lnStr = VAL(RIGHT(tStr,2))
IF BETWEEN(lnStr,1,20)
lcStr = ALLTRIM(STR(lnStr))
lcPhrase = lcPhrase + lcWord&lcStr
ENDIF
IF BETWEEN(lnStr,21,99)
IF lnStr > 20
lcStr = SUBSTR(tStr,2,1)+"0"
lcPhrase = lcPhrase + lcWord&lcStr
ENDIF
IF RIGHT(tStr,1) > '0'
lcStr = RIGHT(tStr,1)
lcPhrase = lcPhrase + lcWord&lcStr
ENDIF
ENDIF
RETURN ALLTRIM(lcPhrase)
*********************************************************
* EOF: NUM2WORD.PRG
*********************************************************
FUNCTION toUpper
LPARAMETERS cString
RETURN UPPER(cString)
FUNCTION toLower
LPARAMETERS cString
RETURN LOWER(cString)
FUNCTION IndexOf
LPARAMETERS cSearchExpression, cExpressionSearched, nOccurrence, lCaseSensitive, lFromRight
LOCAL iReturn
IF VARTYPE(nOccurrence)!='N'
nOccurrence=EVL(nOccurrence,1)
ENDIF
IF nOccurrence > 0
IF lFromRight
iReturn = IIF(lCaseSensitive, ;
RAT(cSearchExpression, cExpressionSearched, nOccurrence), ;
RATC(cSearchExpression, cExpressionSearched, nOccurrence))
ELSE && Normal
iReturn = IIF(lCaseSensitive, ;
AT(cSearchExpression, cExpressionSearched, nOccurrence), ;
ATC(cSearchExpression, cExpressionSearched, nOccurrence))
ENDIF
ELSE
iReturn = 0
ENDIF
RETURN iReturn
FUNCTION LastIndexOf
LPARAMETERS cSearchExpression, cExpressionSearched, nOccurrence, lCaseSensitive
RETURN This.IndexOf(cSearchExpression, cExpressionSearched, nOccurrence, lCaseSensitive, .t.)
FUNCTION PadLeft
LPARAMETERS cString, iLength, cChar
cString = EVL(cString, '')
cChar=EVL(cChar, ' ')
iLength = MAX(LEN(cString),iLength)
RETURN PADL(cString, iLength, cChar)
FUNCTION PadRight
LPARAMETERS cString, iLength, cChar
cString = EVL(cString, '')
cChar=EVL(cChar, ' ')
iLength = MAX(LEN(cString),iLength)
RETURN PADR(cString, iLength, cChar)
FUNCTION PadCenter
LPARAMETERS cString, iLength, cChar
cString = EVL(cString, '')
cChar=EVL(cChar, ' ')
iLength = MAX(LEN(cString),iLength)
RETURN PADC(cString, iLength, cChar)
FUNCTION Replace
LPARAMETERS cString, cFind, cReplace, nStartOccurrence, nNumberOfOccurrences, nFlags
nStartOccurrence=EVL(nStartOccurrence,-1)
nNumberOfOccurrences=EVL(nNumberOfOccurrences,-1)
nFlags = EVL(nFlags,1)
RETURN STRTRAN(cString, cFind, cReplace, nStartOccurrence, nNumberOfOccurrences, nFlags)
FUNCTION Extract
LPARAMETERS cSearchExpression, cBeginDelim, cEndDelim, nOccurrence, nFlags
nOccurrence=EVL(nOccurrence,1)
nFlags=EVL(nFlags,0)
RETURN STREXTRACT(cSearchExpression, cBeginDelim, cEndDelim, nOccurrence, nFlags)
FUNCTION Split
LPARAMETERS aResult, cString, cParseChar, nFlags
LOCAL iRows
nFlags = EVL(nFlags,1)
cParseChar=EVL(cParseChar,' ')
iRows =ALINES(aResult,cString,nFlags,cParseChar)
RETURN iRows
FUNCTION Contains
LPARAMETERS cString, cSubString, nFlags
LOCAL lCaseInsensitive, lExact, lReturn
cSubString=EVL(cSubString,"")
nFlags = EVL(nFlags,0)
lReturn = ! This.IsNullOrEmpty(cString)
IF lReturn
This.getComparisonFlags(nFlags, @lCaseInsensitive, @lExact)
IF lExact
lReturn = This.IndexOf(cSubString, cString, 1, ! lCaseInsensitive)>0
ELSE
lReturn = This.IndexOf(ALLTRIM(cSubString), ALLTRIM(cString), 1, ! lCaseInsensitive)>0
ENDIF
ENDIF
RETURN lReturn
FUNCTION Compare
LPARAMETERS cString1, cString2, nFlags
* Return -1 if cString1 < cString2
* Return 0 if they're the same
* Return 1 if cString2 > cString1
LOCAL lCaseInsensitive, lExact, lReturn
nFlags = EVL(nFlags,0)
This.getComparisonFlags(nFlags, @lCaseInsensitive, @lExact)
cSetExact=SET("Exact")
IF lExact
SET EXACT ON
ELSE
IF LEN(cString2) < LEN(cString1)
cString2 =This.PadLeft(cString2, LEN(cString1))
ELSE
IF LEN(cString2) > LEN(cString1)
cString1 = This.PadLeft(cString1, LEN(cString2))
ENDIF
ENDIF
ENDIF
IF lCaseInsensitive
cString1 = This.ToLower(cString1)
cString2 = This.ToLower(cString2)
ENDIF
lReturn = ICASE(cString1=cString2,0,cString1<cString2,-1,1)
SET EXACT &cSetExact
RETURN lReturn
FUNCTION Occurs
* How often does a substring occur
LPARAMETERS cSubString, cString, nFlags
nFlags = EVL(nFlags,0)
IF This.IsNullOrEmpty(cSubString) OR This.IsNullOrEmpty(cString)
iReturn = 0
ELSE
iReturn = OCCURS(cSubString, cString)
ENDIF
RETURN iReturn
ENDDEFINE