summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAnotherTest <ali.mpfard@gmail.com>2020-11-16 21:43:24 +0330
committerAndreas Kling <kling@serenityos.org>2020-11-27 21:32:41 +0100
commit45e5661296c31fff15d6901f43b1527cbe26f4bf (patch)
tree6c562629f394c598579c73887ad6eb83de36b341
parent6add8b9c054385b119be1c0f731e94d424392dd1 (diff)
downloadserenity-45e5661296c31fff15d6901f43b1527cbe26f4bf.zip
Userland: Add support for 'match' in 'expr'
-rw-r--r--Userland/CMakeLists.txt1
-rw-r--r--Userland/expr.cpp48
2 files changed, 45 insertions, 4 deletions
diff --git a/Userland/CMakeLists.txt b/Userland/CMakeLists.txt
index dc9a100d45..77a338dd7c 100644
--- a/Userland/CMakeLists.txt
+++ b/Userland/CMakeLists.txt
@@ -20,6 +20,7 @@ target_link_libraries(avol LibAudio)
target_link_libraries(checksum LibCrypto)
target_link_libraries(copy LibGUI)
target_link_libraries(disasm LibX86)
+target_link_libraries(expr LibRegex)
target_link_libraries(functrace LibDebug LibX86)
target_link_libraries(html LibWeb)
target_link_libraries(js LibJS LibLine)
diff --git a/Userland/expr.cpp b/Userland/expr.cpp
index 2d227f020c..06f4ae91ce 100644
--- a/Userland/expr.cpp
+++ b/Userland/expr.cpp
@@ -31,6 +31,7 @@
#include <AK/Queue.h>
#include <AK/String.h>
#include <AK/StringView.h>
+#include <LibRegex/Regex.h>
#include <stdio.h>
#include <unistd.h>
@@ -381,7 +382,7 @@ private:
virtual bool truth() const override { return integer() != 0; }
virtual int integer() const override
{
- if (m_op == StringOperation::Substring) {
+ if (m_op == StringOperation::Substring || m_op == StringOperation::Match) {
auto substr = string();
if (auto integer = substr.to_int(); integer.has_value())
return integer.value();
@@ -389,9 +390,6 @@ private:
fail("Not an integer: '{}'", substr);
}
- if (m_op == StringOperation::Match)
- fail("Unimplemented operation 'match'");
-
if (m_op == StringOperation::Index) {
if (auto idx = m_str->string().index_of(m_pos_or_chars->string()); idx.has_value())
return idx.value() + 1;
@@ -417,18 +415,60 @@ private:
if (m_op == StringOperation::Substring)
return safe_substring(m_str->string(), m_pos_or_chars->integer(), m_length->integer());
+ if (m_op == StringOperation::Match) {
+ auto match = m_compiled_regex->match(m_str->string(), PosixFlags::Global);
+ if (m_compiled_regex->parser_result.capture_groups_count == 0) {
+ if (!match.success)
+ return "0";
+
+ size_t count = 0;
+ for (auto& m : match.matches)
+ count += m.view.length();
+
+ return String::number(count);
+ } else {
+ if (!match.success)
+ return "";
+
+ StringBuilder result;
+ for (auto& m : match.capture_group_matches) {
+ for (auto& e : m)
+ result.append(e.view.to_string());
+ }
+
+ return result.build();
+ }
+ }
+
return String::number(integer());
}
virtual Type type() const override
{
if (m_op == StringOperation::Substring)
return Type::String;
+ if (m_op == StringOperation::Match) {
+ if (!m_pos_or_chars)
+ fail("'match' expects a string pattern");
+
+ ensure_regex();
+ if (m_compiled_regex->parser_result.capture_groups_count == 0)
+ return Type::Integer;
+
+ return Type::String;
+ }
return Type::Integer;
}
+ void ensure_regex() const
+ {
+ if (!m_compiled_regex)
+ m_compiled_regex = make<regex::Regex<PosixExtended>>(m_pos_or_chars->string());
+ }
+
StringOperation m_op { StringOperation::Substring };
NonnullOwnPtr<Expression> m_str;
OwnPtr<Expression> m_pos_or_chars, m_length;
+ mutable OwnPtr<regex::Regex<PosixExtended>> m_compiled_regex;
};
NonnullOwnPtr<Expression> Expression::parse(Queue<StringView>& args, Precedence prec)