mirror of
https://github.com/openhab/openhab-addons.git
synced 2025-01-10 07:02:02 +01:00
[mqtt.homeassistant] Implement regex_findall and regex_findall_index filters (#17895)
Signed-off-by: Cody Cutrer <cody@cutrer.us>
This commit is contained in:
parent
a94e4a1c50
commit
f45f29f920
@ -53,11 +53,11 @@ public class HomeAssistantChannelTransformation extends ChannelTransformation {
|
||||
private final Logger logger = LoggerFactory.getLogger(HomeAssistantChannelTransformation.class);
|
||||
|
||||
private final Jinjava jinjava;
|
||||
private final AbstractComponent component;
|
||||
private final AbstractComponent<?> component;
|
||||
private final String template;
|
||||
private final ObjectMapper objectMapper = new ObjectMapper();
|
||||
|
||||
public HomeAssistantChannelTransformation(Jinjava jinjava, AbstractComponent component, String template) {
|
||||
public HomeAssistantChannelTransformation(Jinjava jinjava, AbstractComponent<?> component, String template) {
|
||||
super((String) null);
|
||||
this.jinjava = jinjava;
|
||||
this.component = component;
|
||||
|
@ -14,15 +14,24 @@ package org.openhab.binding.mqtt.homeassistant.internal;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
|
||||
import com.google.re2j.Matcher;
|
||||
import com.google.re2j.Pattern;
|
||||
import com.google.re2j.PatternSyntaxException;
|
||||
import com.hubspot.jinjava.interpret.Context;
|
||||
import com.hubspot.jinjava.interpret.InterpretException;
|
||||
import com.hubspot.jinjava.interpret.InvalidArgumentException;
|
||||
import com.hubspot.jinjava.interpret.InvalidReason;
|
||||
import com.hubspot.jinjava.interpret.JinjavaInterpreter;
|
||||
import com.hubspot.jinjava.interpret.TemplateSyntaxException;
|
||||
import com.hubspot.jinjava.lib.filter.Filter;
|
||||
import com.hubspot.jinjava.lib.fn.ELFunctionDefinition;
|
||||
import com.hubspot.jinjava.util.ObjectTruthValue;
|
||||
@ -39,15 +48,17 @@ public class HomeAssistantJinjaFunctionLibrary {
|
||||
new ELFunctionDefinition("", "iif", Functions.class, "iif", Object.class, Object[].class));
|
||||
context.registerFilter(new SimpleFilter("iif", Functions.class, "iif", Object.class, Object[].class));
|
||||
context.registerFilter(new IsDefinedFilter());
|
||||
context.registerFilter(new RegexFindAllFilter());
|
||||
context.registerFilter(new RegexFindAllIndexFilter());
|
||||
}
|
||||
|
||||
@NonNullByDefault({})
|
||||
private static class SimpleFilter implements Filter {
|
||||
private final String name;
|
||||
private final Method method;
|
||||
private final Class klass;
|
||||
private final Class<?> klass;
|
||||
|
||||
public SimpleFilter(String name, Class klass, String methodName, Class... args) {
|
||||
public SimpleFilter(String name, Class<?> klass, String methodName, Class<?>... args) {
|
||||
this.name = name;
|
||||
this.klass = klass;
|
||||
try {
|
||||
@ -110,9 +121,135 @@ public class HomeAssistantJinjaFunctionLibrary {
|
||||
}
|
||||
}
|
||||
|
||||
// https://www.home-assistant.io/docs/configuration/templating/#regular-expressions
|
||||
// https://github.com/home-assistant/core/blob/2024.12.2/homeassistant/helpers/template.py#L2453
|
||||
@NonNullByDefault({})
|
||||
private static class RegexFindAllFilter implements Filter {
|
||||
@Override
|
||||
public String getName() {
|
||||
return "regex_findall";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object filter(Object var, JinjavaInterpreter interpreter, String... args) {
|
||||
if (args.length > 2) {
|
||||
throw new TemplateSyntaxException(interpreter, getName(),
|
||||
"requires at most 2 arguments (regex string, ignore case)");
|
||||
}
|
||||
|
||||
String find = null;
|
||||
if (args.length >= 1) {
|
||||
find = args[0];
|
||||
}
|
||||
String ignoreCase = null;
|
||||
if (args.length == 2) {
|
||||
ignoreCase = args[1];
|
||||
}
|
||||
|
||||
Matcher m = regexFindAll(var, interpreter, find, ignoreCase);
|
||||
|
||||
List<Object> result = new ArrayList<>();
|
||||
while (m.find()) {
|
||||
result.add(resultForMatcher(m));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
protected Object resultForMatcher(Matcher m) {
|
||||
if (m.groupCount() == 0) {
|
||||
return m.group();
|
||||
} else if (m.groupCount() == 1) {
|
||||
return m.group(1);
|
||||
} else {
|
||||
List<String> groups = new ArrayList<>(m.groupCount());
|
||||
for (int i = 1; i <= m.groupCount(); ++i) {
|
||||
groups.add(m.group(i));
|
||||
}
|
||||
return groups;
|
||||
}
|
||||
}
|
||||
|
||||
protected Matcher regexFindAll(Object var, JinjavaInterpreter interpreter, String find, String ignoreCaseStr) {
|
||||
String s;
|
||||
if (var == null) {
|
||||
s = "None";
|
||||
} else {
|
||||
s = var.toString();
|
||||
}
|
||||
|
||||
boolean ignoreCase = ObjectTruthValue.evaluate(ignoreCaseStr);
|
||||
int flags = 0;
|
||||
if (ignoreCase) {
|
||||
flags = Pattern.CASE_INSENSITIVE;
|
||||
}
|
||||
|
||||
Pattern p;
|
||||
try {
|
||||
if (find instanceof String findString) {
|
||||
p = Pattern.compile(findString, flags);
|
||||
} else if (find == null) {
|
||||
p = Pattern.compile("", flags);
|
||||
} else {
|
||||
throw new InvalidArgumentException(interpreter, this, InvalidReason.REGEX, 0, find);
|
||||
}
|
||||
|
||||
return p.matcher(s);
|
||||
} catch (PatternSyntaxException e) {
|
||||
throw new InvalidArgumentException(interpreter, this, InvalidReason.REGEX, 0, find);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// https://www.home-assistant.io/docs/configuration/templating/#regular-expressions
|
||||
// https://github.com/home-assistant/core/blob/2024.12.2/homeassistant/helpers/template.py#L2448
|
||||
@NonNullByDefault({})
|
||||
private static class RegexFindAllIndexFilter extends RegexFindAllFilter {
|
||||
@Override
|
||||
public String getName() {
|
||||
return "regex_findall_index";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object filter(Object var, JinjavaInterpreter interpreter, String... args) {
|
||||
if (args.length > 3) {
|
||||
throw new TemplateSyntaxException(interpreter, getName(),
|
||||
"requires at most 3 arguments (regex string, index, ignore case)");
|
||||
}
|
||||
|
||||
String find = null;
|
||||
if (args.length >= 1) {
|
||||
find = args[0];
|
||||
}
|
||||
int index = 0;
|
||||
if (args.length >= 2) {
|
||||
index = Integer.valueOf(args[1]);
|
||||
if (index < 0) {
|
||||
throw new InvalidArgumentException(interpreter, this, InvalidReason.POSITIVE_NUMBER, 1, args[1]);
|
||||
}
|
||||
}
|
||||
|
||||
String ignoreCase = null;
|
||||
if (args.length == 3) {
|
||||
ignoreCase = args[2];
|
||||
}
|
||||
|
||||
Matcher m = regexFindAll(var, interpreter, find, ignoreCase);
|
||||
int i = 0;
|
||||
while (i <= index) {
|
||||
if (!m.find()) {
|
||||
break;
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
|
||||
return resultForMatcher(m);
|
||||
}
|
||||
}
|
||||
|
||||
private static class Functions {
|
||||
// https://www.home-assistant.io/docs/configuration/templating/#immediate-if-iif
|
||||
public static Object iif(Object value, Object... results) {
|
||||
public static @Nullable Object iif(@Nullable Object value, @Nullable Object... results) {
|
||||
if (results.length > 3) {
|
||||
throw new IllegalArgumentException("Parameters for function 'iff' do not match");
|
||||
}
|
||||
|
@ -100,6 +100,24 @@ public class HomeAssistantChannelTransformationTests {
|
||||
assertThat(transform("{{ 'hi' | is_defined }}", "{}"), is("hi"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRegexFindall() {
|
||||
assertThat(transform("{{ 'Flight from JFK to LHR' | regex_findall('([A-Z]{3})') }}", ""), is("[JFK, LHR]"));
|
||||
assertThat(transform(
|
||||
"{{ 'button_up_press' | regex_findall('^(?P<button>(?:button_)?[a-z0-9]+)_(?P<action>(?:press|hold)(?:_release)?)$') }}",
|
||||
""), is("[[button_up, press]]"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRegexFindallIndex() {
|
||||
assertThat(transform("{{ 'Flight from JFK to LHR' | regex_findall_index('([A-Z]{3})', 0) }}", ""), is("JFK"));
|
||||
assertThat(transform("{{ 'Flight from JFK to LHR' | regex_findall_index('([A-Z]{3})', 1) }}", ""), is("LHR"));
|
||||
assertThat(transform("{{ ['JFK', 'LHR'] | regex_findall_index('([A-Z]{3})', 1) }}", ""), is("LHR"));
|
||||
assertThat(transform(
|
||||
"{{ 'button_up_press' | regex_findall_index('^(?P<button>(?:button_)?[a-z0-9]+)_(?P<action>(?:press|hold)(?:_release)?)$') }}",
|
||||
""), is("[button_up, press]"));
|
||||
}
|
||||
|
||||
protected @Nullable String transform(String template, String value) {
|
||||
return transformation.apply(template, value).orElse(null);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user