From 45e5661296c31fff15d6901f43b1527cbe26f4bf Mon Sep 17 00:00:00 2001 From: AnotherTest Date: Mon, 16 Nov 2020 21:43:24 +0330 Subject: Userland: Add support for 'match' in 'expr' --- Userland/CMakeLists.txt | 1 + Userland/expr.cpp | 48 ++++++++++++++++++++++++++++++++++++++++++++---- 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 #include #include +#include #include #include @@ -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>(m_pos_or_chars->string()); + } + StringOperation m_op { StringOperation::Substring }; NonnullOwnPtr m_str; OwnPtr m_pos_or_chars, m_length; + mutable OwnPtr> m_compiled_regex; }; NonnullOwnPtr Expression::parse(Queue& args, Precedence prec) -- cgit v1.2.3