1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package com.healthmarketscience.jackcess.impl.expr;
17
18 import java.math.BigDecimal;
19
20 import com.healthmarketscience.jackcess.expr.EvalContext;
21 import com.healthmarketscience.jackcess.expr.EvalException;
22 import com.healthmarketscience.jackcess.expr.Function;
23 import com.healthmarketscience.jackcess.expr.LocaleContext;
24 import com.healthmarketscience.jackcess.expr.Value;
25 import static com.healthmarketscience.jackcess.impl.expr.DefaultFunctions.*;
26 import static com.healthmarketscience.jackcess.impl.expr.FunctionSupport.*;
27
28
29
30
31
32 public class DefaultTextFunctions
33 {
34
35
36 private static final int STR_CONV_MASK = 0x03;
37
38 private DefaultTextFunctions() {}
39
40 static void init() {
41
42 }
43
44 public static final Function ASC = registerFunc(new Func1("Asc") {
45 @Override
46 protected Value../com/healthmarketscience/jackcess/expr/Value.html#Value">Value eval1(EvalContext ctx, Value param1) {
47 String str = param1.getAsString(ctx);
48 int len = str.length();
49 if(len == 0) {
50 throw new EvalException("No characters in string");
51 }
52 int lv = str.charAt(0);
53 if((lv < 0) || (lv > 255)) {
54 throw new EvalException("Character code '" + lv +
55 "' out of range ");
56 }
57 return ValueSupport.toValue(lv);
58 }
59 });
60
61 public static final Function ASCW = registerFunc(new Func1("AscW") {
62 @Override
63 protected Value../com/healthmarketscience/jackcess/expr/Value.html#Value">Value eval1(EvalContext ctx, Value param1) {
64 String str = param1.getAsString(ctx);
65 int len = str.length();
66 if(len == 0) {
67 throw new EvalException("No characters in string");
68 }
69 int lv = str.charAt(0);
70 return ValueSupport.toValue(lv);
71 }
72 });
73
74 public static final Function CHR = registerStringFunc(new Func1NullIsNull("Chr") {
75 @Override
76 protected Value../com/healthmarketscience/jackcess/expr/Value.html#Value">Value eval1(EvalContext ctx, Value param1) {
77 int lv = param1.getAsLongInt(ctx);
78 if((lv < 0) || (lv > 255)) {
79 throw new EvalException("Character code '" + lv +
80 "' out of range ");
81 }
82 char[] cs = Character.toChars(lv);
83 return ValueSupport.toValue(new String(cs));
84 }
85 });
86
87 public static final Function CHRW = registerStringFunc(new Func1NullIsNull("ChrW") {
88 @Override
89 protected Value../com/healthmarketscience/jackcess/expr/Value.html#Value">Value eval1(EvalContext ctx, Value param1) {
90 int lv = param1.getAsLongInt(ctx);
91 char[] cs = Character.toChars(lv);
92 return ValueSupport.toValue(new String(cs));
93 }
94 });
95
96 public static final Function STR = registerStringFunc(new Func1NullIsNull("Str") {
97 @Override
98 protected Value../com/healthmarketscience/jackcess/expr/Value.html#Value">Value eval1(EvalContext ctx, Value param1) {
99 BigDecimal bd = param1.getAsBigDecimal(ctx);
100 String str = bd.toPlainString();
101 if(bd.compareTo(BigDecimal.ZERO) >= 0) {
102 str = " " + str;
103 }
104 return ValueSupport.toValue(str);
105 }
106 });
107
108 public static final Function INSTR = registerFunc(new FuncVar("InStr", 2, 4) {
109 @Override
110 protected Value/com/healthmarketscience/jackcess/expr/Value.html#Value">Value evalVar(EvalContext ctx, Value[] params) {
111 int idx = 0;
112 int start = 0;
113 if(params.length > 2) {
114
115 start = params[0].getAsLongInt(ctx) - 1;
116 ++idx;
117 }
118 Value param1 = params[idx++];
119 if(param1.isNull()) {
120 return param1;
121 }
122 String s1 = param1.getAsString(ctx);
123 int s1Len = s1.length();
124 if(s1Len == 0) {
125 return ValueSupport.ZERO_VAL;
126 }
127 Value param2 = params[idx++];
128 if(param2.isNull()) {
129 return param2;
130 }
131 String s2 = param2.getAsString(ctx);
132 int s2Len = s2.length();
133 if(s2Len == 0) {
134
135 return ValueSupport.toValue(start + 1);
136 }
137 boolean ignoreCase = getIgnoreCase(ctx, params, 3);
138 int end = s1Len - s2Len;
139 while(start < end) {
140 if(s1.regionMatches(ignoreCase, start, s2, 0, s2Len)) {
141
142 return ValueSupport.toValue(start + 1);
143 }
144 ++start;
145 }
146 return ValueSupport.ZERO_VAL;
147 }
148 });
149
150 public static final Function INSTRREV = registerFunc(new FuncVar("InStrRev", 2, 4) {
151 @Override
152 protected Value/com/healthmarketscience/jackcess/expr/Value.html#Value">Value evalVar(EvalContext ctx, Value[] params) {
153 Value param1 = params[0];
154 if(param1.isNull()) {
155 return param1;
156 }
157 String s1 = param1.getAsString(ctx);
158 int s1Len = s1.length();
159 if(s1Len == 0) {
160 return ValueSupport.ZERO_VAL;
161 }
162 Value param2 = params[1];
163 if(param2.isNull()) {
164 return param2;
165 }
166 String s2 = param2.getAsString(ctx);
167 int s2Len = s2.length();
168 int start = s1Len - 1;
169 if(s2Len == 0) {
170
171 return ValueSupport.toValue(start + 1);
172 }
173 if(params.length > 2) {
174 start = params[2].getAsLongInt(ctx);
175 if(start == -1) {
176 start = s1Len;
177 }
178
179 --start;
180 }
181 boolean ignoreCase = getIgnoreCase(ctx, params, 3);
182 start = Math.min(s1Len - s2Len, start - s2Len + 1);
183 while(start >= 0) {
184 if(s1.regionMatches(ignoreCase, start, s2, 0, s2Len)) {
185
186 return ValueSupport.toValue(start + 1);
187 }
188 --start;
189 }
190 return ValueSupport.ZERO_VAL;
191 }
192 });
193
194 public static final Function LCASE = registerStringFunc(new Func1NullIsNull("LCase") {
195 @Override
196 protected Value../com/healthmarketscience/jackcess/expr/Value.html#Value">Value eval1(EvalContext ctx, Value param1) {
197 String str = param1.getAsString(ctx);
198 return ValueSupport.toValue(str.toLowerCase());
199 }
200 });
201
202 public static final Function UCASE = registerStringFunc(new Func1NullIsNull("UCase") {
203 @Override
204 protected Value../com/healthmarketscience/jackcess/expr/Value.html#Value">Value eval1(EvalContext ctx, Value param1) {
205 String str = param1.getAsString(ctx);
206 return ValueSupport.toValue(str.toUpperCase());
207 }
208 });
209
210 public static final Function LEFT = registerStringFunc(new Func2("Left") {
211 @Override
212 protected Valuef="../../../../../com/healthmarketscience/jackcess/expr/Value.html#Value">Value../com/healthmarketscience/jackcess/expr/Value.html#Value">Value eval2(EvalContext ctx, Valuef="../../../../../com/healthmarketscience/jackcess/expr/Value.html#Value">Value param1, Value param2) {
213 if(param1.isNull()) {
214 return param1;
215 }
216 String str = param1.getAsString(ctx);
217 int len = Math.min(str.length(), param2.getAsLongInt(ctx));
218 return ValueSupport.toValue(str.substring(0, len));
219 }
220 });
221
222 public static final Function RIGHT = registerStringFunc(new Func2("Right") {
223 @Override
224 protected Valuef="../../../../../com/healthmarketscience/jackcess/expr/Value.html#Value">Value../com/healthmarketscience/jackcess/expr/Value.html#Value">Value eval2(EvalContext ctx, Valuef="../../../../../com/healthmarketscience/jackcess/expr/Value.html#Value">Value param1, Value param2) {
225 if(param1.isNull()) {
226 return param1;
227 }
228 String str = param1.getAsString(ctx);
229 int strLen = str.length();
230 int len = Math.min(strLen, param2.getAsLongInt(ctx));
231 return ValueSupport.toValue(str.substring(strLen - len, strLen));
232 }
233 });
234
235 public static final Function MID = registerStringFunc(new FuncVar("Mid", 2, 3) {
236 @Override
237 protected Value/com/healthmarketscience/jackcess/expr/Value.html#Value">Value evalVar(EvalContext ctx, Value[] params) {
238 Value param1 = params[0];
239 if(param1.isNull()) {
240 return param1;
241 }
242 String str = param1.getAsString(ctx);
243 int strLen = str.length();
244
245 int start = Math.min(strLen, params[1].getAsLongInt(ctx) - 1);
246 int len = Math.min(
247 ((params.length > 2) ? params[2].getAsLongInt(ctx) : strLen),
248 (strLen - start));
249 return ValueSupport.toValue(str.substring(start, start + len));
250 }
251 });
252
253 public static final Function LEN = registerFunc(new Func1NullIsNull("Len") {
254 @Override
255 protected Value../com/healthmarketscience/jackcess/expr/Value.html#Value">Value eval1(EvalContext ctx, Value param1) {
256 String str = param1.getAsString(ctx);
257 return ValueSupport.toValue(str.length());
258 }
259 });
260
261 public static final Function LTRIM = registerStringFunc(new Func1NullIsNull("LTrim") {
262 @Override
263 protected Value../com/healthmarketscience/jackcess/expr/Value.html#Value">Value eval1(EvalContext ctx, Value param1) {
264 String str = param1.getAsString(ctx);
265 return ValueSupport.toValue(trim(str, true, false));
266 }
267 });
268
269 public static final Function RTRIM = registerStringFunc(new Func1NullIsNull("RTrim") {
270 @Override
271 protected Value../com/healthmarketscience/jackcess/expr/Value.html#Value">Value eval1(EvalContext ctx, Value param1) {
272 String str = param1.getAsString(ctx);
273 return ValueSupport.toValue(trim(str, false, true));
274 }
275 });
276
277 public static final Function TRIM = registerStringFunc(new Func1NullIsNull("Trim") {
278 @Override
279 protected Value../com/healthmarketscience/jackcess/expr/Value.html#Value">Value eval1(EvalContext ctx, Value param1) {
280 String str = param1.getAsString(ctx);
281 return ValueSupport.toValue(trim(str, true, true));
282 }
283 });
284
285 public static final Function REPLACE = registerStringFunc(new FuncVar("Replace", 3, 6) {
286 @Override
287 protected Value/com/healthmarketscience/jackcess/expr/Value.html#Value">Value evalVar(EvalContext ctx, Value[] params) {
288 String str = params[0].getAsString(ctx);
289 String searchStr = params[1].getAsString(ctx);
290 String replStr = params[2].getAsString(ctx);
291
292 int strLen = str.length();
293
294 int start = getOptionalIntParam(ctx, params, 3, 1) - 1;
295 int count = getOptionalIntParam(ctx, params, 4, -1);
296 boolean ignoreCase = getIgnoreCase(ctx, params, 5);
297
298 if(start >= strLen) {
299 return ValueSupport.EMPTY_STR_VAL;
300 }
301
302 int searchLen = searchStr.length();
303 if((searchLen == 0) || (count == 0)) {
304 String result = str;
305 if(start > 0) {
306 result = str.substring(start);
307 }
308 return ValueSupport.toValue(result);
309 }
310
311 if(count < 0) {
312 count = strLen;
313 }
314
315 StringBuilder result = new StringBuilder(strLen);
316
317 int matchCount = 0;
318 for(int i = start; i < strLen; ++i) {
319 if((matchCount < count) &&
320 str.regionMatches(ignoreCase, i, searchStr, 0, searchLen)) {
321 result.append(replStr);
322 ++matchCount;
323 i += searchLen - 1;
324 } else {
325 result.append(str.charAt(i));
326 }
327 }
328
329 return ValueSupport.toValue(result.toString());
330 }
331 });
332
333 public static final Function SPACE = registerStringFunc(new Func1("Space") {
334 @Override
335 protected Value../com/healthmarketscience/jackcess/expr/Value.html#Value">Value eval1(EvalContext ctx, Value param1) {
336 int lv = param1.getAsLongInt(ctx);
337 return ValueSupport.toValue(nchars(lv, ' '));
338 }
339 });
340
341 public static final Function STRCOMP = registerFunc(new FuncVar("StrComp", 2, 3) {
342 @Override
343 protected Value/com/healthmarketscience/jackcess/expr/Value.html#Value">Value evalVar(EvalContext ctx, Value[] params) {
344 Value param1 = params[0];
345 Value param2 = params[1];
346 if(param1.isNull() || param2.isNull()) {
347 return ValueSupport.NULL_VAL;
348 }
349 String s1 = param1.getAsString(ctx);
350 String s2 = param2.getAsString(ctx);
351 boolean ignoreCase = getIgnoreCase(ctx, params, 2);
352 int cmp = (ignoreCase ?
353 s1.compareToIgnoreCase(s2) : s1.compareTo(s2));
354
355 return ((cmp < 0) ? ValueSupport.NEG_ONE_VAL :
356 ((cmp > 0) ? ValueSupport.ONE_VAL :
357 ValueSupport.ZERO_VAL));
358 }
359 });
360
361 @SuppressWarnings("deprecation")
362 public static final Function STRCONV = registerStringFunc(new FuncVar("StrConv", 2, 3) {
363 @Override
364 protected Value/com/healthmarketscience/jackcess/expr/Value.html#Value">Value evalVar(EvalContext ctx, Value[] params) {
365 Value param1 = params[0];
366 if(param1.isNull()) {
367 return ValueSupport.NULL_VAL;
368 }
369
370 String str = param1.getAsString(ctx);
371 int conversion = params[1].getAsLongInt(ctx);
372
373
374
375 int caseConv = STR_CONV_MASK & conversion;
376 int charConv = (~STR_CONV_MASK) & conversion;
377
378 switch(caseConv) {
379 case 1:
380
381 str = str.toUpperCase();
382 break;
383 case 2:
384
385 str = str.toLowerCase();
386 break;
387 case 3:
388
389 str = org.apache.commons.lang3.text.WordUtils.capitalize(
390 str.toLowerCase());
391 break;
392 default:
393
394 }
395
396 if(charConv != 0) {
397
398 if(charConv != 64) {
399 throw new EvalException("Unsupported character conversion " + charConv);
400 }
401 }
402
403 return ValueSupport.toValue(str);
404 }
405 });
406
407 public static final Function STRING = registerStringFunc(new Func2("String") {
408 @Override
409 protected Valuef="../../../../../com/healthmarketscience/jackcess/expr/Value.html#Value">Value../com/healthmarketscience/jackcess/expr/Value.html#Value">Value eval2(EvalContext ctx, Valuef="../../../../../com/healthmarketscience/jackcess/expr/Value.html#Value">Value param1, Value param2) {
410 if(param1.isNull() || param2.isNull()) {
411 return ValueSupport.NULL_VAL;
412 }
413 int lv = param1.getAsLongInt(ctx);
414 char c = (char)(param2.getAsString(ctx).charAt(0) % 256);
415 return ValueSupport.toValue(nchars(lv, c));
416 }
417 });
418
419 public static final Function STRREVERSE = registerFunc(new Func1("StrReverse") {
420 @Override
421 protected Value../com/healthmarketscience/jackcess/expr/Value.html#Value">Value eval1(EvalContext ctx, Value param1) {
422 String str = param1.getAsString(ctx);
423 return ValueSupport.toValue(
424 new StringBuilder(str).reverse().toString());
425 }
426 });
427
428 public static final Function FORMAT = registerStringFunc(new FuncVar("Format", 1, 4) {
429 @Override
430 protected Value/com/healthmarketscience/jackcess/expr/Value.html#Value">Value evalVar(EvalContext ctx, Value[] params) {
431
432 Value expr = params[0];
433 if(params.length < 2) {
434
435 if(expr.isNull()) {
436 return ValueSupport.NULL_VAL;
437 }
438 return ValueSupport.toValue(expr.getAsString(ctx));
439 }
440
441 String fmtStr = params[1].getAsString(ctx);
442 int firstDay = DefaultDateFunctions.getFirstDayParam(ctx, params, 2);
443 int firstWeekType = DefaultDateFunctions.getFirstWeekTypeParam(ctx, params, 3);
444
445 return FormatUtil.format(ctx, expr, fmtStr, firstDay, firstWeekType);
446 }
447 });
448
449 private static String nchars(int num, char c) {
450 StringBuilder sb = new StringBuilder(num);
451 nchars(sb, num, c);
452 return sb.toString();
453 }
454
455 static void nchars(StringBuilder sb, int num, char c) {
456 for(int i = 0; i < num; ++i) {
457 sb.append(c);
458 }
459 }
460
461 private static String trim(String str, boolean doLeft, boolean doRight) {
462 int start = 0;
463 int end = str.length();
464
465 if(doLeft) {
466 while((start < end) && (str.charAt(start) == ' ')) {
467 ++start;
468 }
469 }
470 if(doRight) {
471 while((start < end) && (str.charAt(end - 1) == ' ')) {
472 --end;
473 }
474 }
475 return str.substring(start, end);
476 }
477
478 private static boolean getIgnoreCase(EvalContext ctx, Value[] params, int idx) {
479 boolean ignoreCase = true;
480 if(params.length > idx) {
481 ignoreCase = doIgnoreCase(ctx, params[idx]);
482 }
483 return ignoreCase;
484 }
485
486 private static boolean doIgnoreCase(LocaleContext ctx, Value paramCmp) {
487 int cmpType = paramCmp.getAsLongInt(ctx);
488 switch(cmpType) {
489 case -1:
490
491 case 0:
492
493 return false;
494 case 1:
495
496 return true;
497 default:
498
499 throw new EvalException("Unsupported compare type " + cmpType);
500 }
501 }
502
503
504 }