diff --git a/doc/18-library-reference.md b/doc/18-library-reference.md
index 592178664c..f76798a3bb 100644
--- a/doc/18-library-reference.md
+++ b/doc/18-library-reference.md
@@ -587,6 +587,65 @@ true
false
```
+### regex\_match
+
+Signature:
+
+```
+function regex_match(pattern, value)
+```
+
+If the regular expression `pattern` matches the string `value`,
+returns an array with the first match inside the whole string
+and the submatches of the match declared with parentheses.
+
+Otherwise returns null.
+
+Examples:
+
+```
+$ icinga2 console
+Icinga 2 (version: v2.13.0)
+<1> => regex_match("foo", "bar")
+null
+<2> => regex_match("foo", "foo")
+[ "foo" ]
+<3> => regex_match("f(o)o", "foo")
+[ "foo", "o" ]
+```
+
+```
+object Host "example.com" {
+ check_command = "passive"
+
+ vars.http_urls = [
+ "http://monitor.example.com/icingaweb2",
+ "https://logs.example.com",
+ "http://cloud.example.com:5000"
+ ]
+}
+
+apply Service "http-" for (url in host.vars.http_urls) {
+ check_command = "http"
+
+ var match = regex_match({{{http(s?)://([^:/]+)((?::\d+)?)((?:/.*)?)}}}, url)
+
+ if (match[1]) {
+ vars.http_ssl = true
+ }
+
+ vars.http_address = match[2]
+
+ if (match[3]) {
+ vars.http_port = match[3].substr(1)
+ }
+
+ if (match[4]) {
+ vars.http_uri = match[4]
+ }
+}
+```
+
### sleep
Signature:
diff --git a/lib/base/scriptutils.cpp b/lib/base/scriptutils.cpp
index 3611799ffc..63920e2eef 100644
--- a/lib/base/scriptutils.cpp
+++ b/lib/base/scriptutils.cpp
@@ -18,6 +18,7 @@
#include
#include
#include
+#include
#ifdef _WIN32
#include
#endif /* _WIN32 */
@@ -25,6 +26,7 @@
using namespace icinga;
REGISTER_SAFE_FUNCTION(System, regex, &ScriptUtils::Regex, "pattern:text:mode");
+REGISTER_SAFE_FUNCTION(System, regex_match, &ScriptUtils::RegexMatch, "pattern:text");
REGISTER_SAFE_FUNCTION(System, match, &ScriptUtils::Match, "pattern:text:mode");
REGISTER_SAFE_FUNCTION(System, cidr_match, &ScriptUtils::CidrMatch, "pattern:ip:mode");
REGISTER_SAFE_FUNCTION(System, len, &ScriptUtils::Len, "value");
@@ -148,6 +150,27 @@ bool ScriptUtils::Regex(const std::vector& args)
}
}
+Array::Ptr ScriptUtils::RegexMatch(const String& pattern, const String& text)
+{
+ boost::regex expr (pattern.GetData());
+ boost::smatch what;
+
+ if (!boost::regex_search(text.GetData(), what, expr)) {
+ return nullptr;
+ }
+
+ Array::Ptr res = new Array();
+ ObjectLock oLock (res);
+
+ res->Reserve(what.size());
+
+ for (auto& submatch : what) {
+ res->Add(String(submatch.str()));
+ }
+
+ return std::move(res);
+}
+
bool ScriptUtils::Match(const std::vector& args)
{
if (args.size() < 2)
diff --git a/lib/base/scriptutils.hpp b/lib/base/scriptutils.hpp
index 7bd3e8b9d3..0890f7cb01 100644
--- a/lib/base/scriptutils.hpp
+++ b/lib/base/scriptutils.hpp
@@ -24,6 +24,7 @@ class ScriptUtils
static double CastNumber(const Value& value);
static bool CastBool(const Value& value);
static bool Regex(const std::vector& args);
+ static Array::Ptr RegexMatch(const String& pattern, const String& text);
static bool Match(const std::vector& args);
static bool CidrMatch(const std::vector& args);
static double Len(const Value& value);
diff --git a/test/config-ops.cpp b/test/config-ops.cpp
index dfbef2530f..3116bae1b6 100644
--- a/test/config-ops.cpp
+++ b/test/config-ops.cpp
@@ -158,6 +158,12 @@ BOOST_AUTO_TEST_CASE(advanced)
expr = ConfigCompiler::CompileText("", R"(regex("^Hello", "Hello World"))");
BOOST_CHECK(expr->Evaluate(frame).GetValue());
+ expr = ConfigCompiler::CompileText("", R"(regex_match("f(o)o", "foo") == [ "foo", "o" ])");
+ BOOST_CHECK(expr->Evaluate(frame).GetValue());
+
+ expr = ConfigCompiler::CompileText("", R"(var nl = regex_match("f(o)o", "bar"); nl == null && typeof(nl) == Object)");
+ BOOST_CHECK(expr->Evaluate(frame).GetValue());
+
expr = ConfigCompiler::CompileText("", "__boost_test()");
BOOST_CHECK_THROW(expr->Evaluate(frame).GetValue(), ScriptError);