您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

PatternColumnPredicate.java 3.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127
  1. /*
  2. Copyright (c) 2020 James Ahlborn
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. */
  13. package com.healthmarketscience.jackcess.util;
  14. import java.io.IOException;
  15. import java.util.function.Predicate;
  16. import java.util.regex.Pattern;
  17. import com.healthmarketscience.jackcess.RuntimeIOException;
  18. import com.healthmarketscience.jackcess.impl.ColumnImpl;
  19. import com.healthmarketscience.jackcess.impl.expr.Expressionator;
  20. /**
  21. * Predicate which tests a column value against a {@link Pattern}. The static
  22. * factory methods can be used to construct the Pattern from various forms of
  23. * wildcard pattern syntaxes.
  24. *
  25. * This class can be used as a value pattern in the various Cursor search
  26. * methods, e.g. {@link com.healthmarketscience.jackcess.Cursor#findFirstRow(com.healthmarketscience.jackcess.Column,Object)}.
  27. *
  28. * @author James Ahlborn
  29. */
  30. public class PatternColumnPredicate implements Predicate<Object>
  31. {
  32. private static final int LIKE_REGEX_FLAGS = Pattern.DOTALL;
  33. private static final int CI_LIKE_REGEX_FLAGS =
  34. LIKE_REGEX_FLAGS | Pattern.CASE_INSENSITIVE |
  35. Pattern.UNICODE_CASE;
  36. private final Pattern _pattern;
  37. public PatternColumnPredicate(Pattern pattern) {
  38. _pattern = pattern;
  39. }
  40. @Override
  41. public boolean test(Object value) {
  42. try {
  43. // convert column value to string
  44. CharSequence cs = ColumnImpl.toCharSequence(value);
  45. return _pattern.matcher(cs).matches();
  46. } catch(IOException e) {
  47. throw new RuntimeIOException("Could not coerece column value to string", e);
  48. }
  49. }
  50. private static Pattern sqlLikeToRegex(
  51. String value, boolean caseInsensitive)
  52. {
  53. StringBuilder sb = new StringBuilder(value.length());
  54. for(int i = 0; i < value.length(); ++i) {
  55. char c = value.charAt(i);
  56. if(c == '%') {
  57. sb.append(".*");
  58. } else if(c == '_') {
  59. sb.append('.');
  60. } else if(c == '\\') {
  61. if(i + 1 < value.length()) {
  62. appendLiteralChar(sb, value.charAt(++i));
  63. }
  64. } else {
  65. appendLiteralChar(sb, c);
  66. }
  67. }
  68. int flags = (caseInsensitive ? CI_LIKE_REGEX_FLAGS : LIKE_REGEX_FLAGS);
  69. return Pattern.compile(sb.toString(), flags);
  70. }
  71. private static void appendLiteralChar(StringBuilder sb, char c) {
  72. if(Expressionator.isRegexSpecialChar(c)) {
  73. sb.append('\\');
  74. }
  75. sb.append(c);
  76. }
  77. /**
  78. * @return a PatternColumnPredicate which tests values against the given ms
  79. * access wildcard pattern (always case insensitive)
  80. */
  81. public static PatternColumnPredicate forAccessLike(String pattern) {
  82. return new PatternColumnPredicate(Expressionator.likePatternToRegex(pattern));
  83. }
  84. /**
  85. * @return a PatternColumnPredicate which tests values against the given sql
  86. * like pattern (supports escape char '\')
  87. */
  88. public static PatternColumnPredicate forSqlLike(String pattern) {
  89. return forSqlLike(pattern, false);
  90. }
  91. /**
  92. * @return a PatternColumnPredicate which tests values against the given sql
  93. * like pattern (supports escape char '\'), optionally case
  94. * insensitive
  95. */
  96. public static PatternColumnPredicate forSqlLike(
  97. String pattern, boolean caseInsensitive) {
  98. return new PatternColumnPredicate(sqlLikeToRegex(pattern, caseInsensitive));
  99. }
  100. /**
  101. * @return a PatternColumnPredicate which tests values against the given
  102. * java regex pattern
  103. */
  104. public static PatternColumnPredicate forJavaRegex(String pattern) {
  105. return new PatternColumnPredicate(Pattern.compile(pattern));
  106. }
  107. }