1
2
3
4
5
6 package dev.metaschema.core.metapath.function.library;
7
8 import java.util.List;
9 import java.util.regex.Pattern;
10 import java.util.regex.PatternSyntaxException;
11
12 import dev.metaschema.core.metapath.DynamicContext;
13 import dev.metaschema.core.metapath.MetapathConstants;
14 import dev.metaschema.core.metapath.function.FunctionUtils;
15 import dev.metaschema.core.metapath.function.IArgument;
16 import dev.metaschema.core.metapath.function.IFunction;
17 import dev.metaschema.core.metapath.function.regex.RegexUtil;
18 import dev.metaschema.core.metapath.function.regex.RegularExpressionMetapathException;
19 import dev.metaschema.core.metapath.item.IItem;
20 import dev.metaschema.core.metapath.item.ISequence;
21 import dev.metaschema.core.metapath.item.atomic.IBooleanItem;
22 import dev.metaschema.core.metapath.item.atomic.IStringItem;
23 import dev.metaschema.core.util.ObjectUtils;
24 import edu.umd.cs.findbugs.annotations.NonNull;
25 import edu.umd.cs.findbugs.annotations.Nullable;
26
27
28
29
30
31
32 public final class FnMatches {
33 @NonNull
34 private static final String NAME = "matches";
35
36 @NonNull
37 static final IFunction SIGNATURE_TWO_ARG = IFunction.builder()
38 .name(NAME)
39 .namespace(MetapathConstants.NS_METAPATH_FUNCTIONS)
40 .deterministic()
41 .contextIndependent()
42 .focusIndependent()
43 .argument(IArgument.builder()
44 .name("input")
45 .type(IStringItem.type())
46 .zeroOrOne()
47 .build())
48 .argument(IArgument.builder()
49 .name("pattern")
50 .type(IStringItem.type())
51 .one()
52 .build())
53 .returnType(IBooleanItem.type())
54 .returnOne()
55 .functionHandler(FnMatches::executeTwoArg)
56 .build();
57
58 @NonNull
59 static final IFunction SIGNATURE_THREE_ARG = IFunction.builder()
60 .name(NAME)
61 .namespace(MetapathConstants.NS_METAPATH_FUNCTIONS)
62 .deterministic()
63 .contextIndependent()
64 .focusIndependent()
65 .argument(IArgument.builder()
66 .name("input")
67 .type(IStringItem.type())
68 .zeroOrOne()
69 .build())
70 .argument(IArgument.builder()
71 .name("pattern")
72 .type(IStringItem.type())
73 .one()
74 .build())
75 .argument(IArgument.builder()
76 .name("flags")
77 .type(IStringItem.type())
78 .one()
79 .build())
80 .returnType(IBooleanItem.type())
81 .returnOne()
82 .functionHandler(FnMatches::executeThreeArg)
83 .build();
84
85
86 @SuppressWarnings("unused")
87 @NonNull
88 private static ISequence<IBooleanItem> executeTwoArg(
89 @NonNull IFunction function,
90 @NonNull List<ISequence<?>> arguments,
91 @NonNull DynamicContext dynamicContext,
92 IItem focus) {
93 IStringItem input = FunctionUtils.asTypeOrNull(arguments.get(0).getFirstItem(true));
94 IStringItem pattern = ObjectUtils.requireNonNull(FunctionUtils.asTypeOrNull(arguments.get(1).getFirstItem(true)));
95
96 return execute(input, pattern, IStringItem.valueOf(""));
97 }
98
99 @SuppressWarnings("unused")
100 @NonNull
101 private static ISequence<IBooleanItem> executeThreeArg(
102 @NonNull IFunction function,
103 @NonNull List<ISequence<?>> arguments,
104 @NonNull DynamicContext dynamicContext,
105 IItem focus) {
106 IStringItem input = FunctionUtils.asTypeOrNull(arguments.get(0).getFirstItem(true));
107 IStringItem pattern = ObjectUtils.requireNonNull(FunctionUtils.asTypeOrNull(arguments.get(1).getFirstItem(true)));
108 IStringItem flags = ObjectUtils.requireNonNull(FunctionUtils.asTypeOrNull(arguments.get(2).getFirstItem(true)));
109
110 return execute(input, pattern, flags);
111 }
112
113 @NonNull
114 private static ISequence<IBooleanItem> execute(
115 @Nullable IStringItem input,
116 @NonNull IStringItem pattern,
117 @NonNull IStringItem flags) {
118 return input == null
119 ? ISequence.empty()
120 : ISequence.of(
121 IBooleanItem.valueOf(
122 fnMatches(input.asString(), pattern.asString(), flags.asString())));
123 }
124
125
126
127
128
129
130
131
132
133
134
135
136
137 public static boolean fnMatches(@NonNull String input, @NonNull String pattern, @NonNull String flags) {
138 try {
139 return Pattern.compile(pattern, RegexUtil.parseFlags(flags))
140 .matcher(input).find();
141 } catch (PatternSyntaxException ex) {
142 throw new RegularExpressionMetapathException(
143 RegularExpressionMetapathException.INVALID_EXPRESSION,
144 "Invalid regular expression pattern: '" + pattern + "'",
145 ex);
146 } catch (IllegalArgumentException ex) {
147 throw new RegularExpressionMetapathException(
148 RegularExpressionMetapathException.INVALID_FLAG,
149 "Invalid regular expression flags: '" + flags + "'",
150 ex);
151 }
152 }
153
154 private FnMatches() {
155
156 }
157 }