diff options
author | AnotherTest <ali.mpfard@gmail.com> | 2020-11-16 21:43:24 +0330 |
---|---|---|
committer | Andreas Kling <kling@serenityos.org> | 2020-11-27 21:32:41 +0100 |
commit | 45e5661296c31fff15d6901f43b1527cbe26f4bf (patch) | |
tree | 6c562629f394c598579c73887ad6eb83de36b341 | |
parent | 6add8b9c054385b119be1c0f731e94d424392dd1 (diff) | |
download | serenity-45e5661296c31fff15d6901f43b1527cbe26f4bf.zip |
Userland: Add support for 'match' in 'expr'
-rw-r--r-- | Userland/CMakeLists.txt | 1 | ||||
-rw-r--r-- | 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 <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) |