Skip to content

Commit 543ddd1

Browse files
nkaralisliss-h
andauthored
Feature: Make regex from literal (#408)
Co-authored-by: Liss Heidrich <31625940+liss-h@users.noreply.github.com>
1 parent 0d84ecb commit 543ddd1

10 files changed

Lines changed: 48 additions & 63 deletions

File tree

private/rdf4cpp/regex/RegexReplacerImpl.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -74,8 +74,8 @@ static std::string translate_rewrite(std::string_view const s) {
7474

7575
} // namespace detail
7676

77-
RegexReplacer::Impl::Impl(Regex::Impl const &regex, std::string_view const rewrite) : regex{&regex},
78-
rewrite{regex.flags.contains(RegexFlag::Literal)
77+
RegexReplacer::Impl::Impl(std::shared_ptr<Regex::Impl const> regex, std::string_view const rewrite) : regex{std::move(regex)},
78+
rewrite{this->regex->flags.contains(RegexFlag::Literal)
7979
? rewrite
8080
: detail::translate_rewrite(rewrite)} {
8181
std::string err{};
@@ -87,7 +87,7 @@ RegexReplacer::Impl::Impl(Regex::Impl const &regex, std::string_view const rewri
8787
}
8888
}
8989

90-
void RegexReplacer::Impl::regex_replace(std::string &str) const noexcept {
90+
void RegexReplacer::Impl::regex_replace(std::string &str) const {
9191
RE2::GlobalReplace(&str, this->regex->regex, this->rewrite);
9292
}
9393

private/rdf4cpp/regex/RegexReplacerImpl.hpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,11 @@
77
namespace rdf4cpp::regex {
88

99
struct RegexReplacer::Impl {
10-
Regex::Impl const *regex;
10+
std::shared_ptr<Regex::Impl const> regex;
1111
std::string rewrite;
1212

13-
Impl(Regex::Impl const &regex, std::string_view rewrite);
14-
void regex_replace(std::string &str) const noexcept;
13+
Impl(std::shared_ptr<Regex::Impl const> regex, std::string_view rewrite);
14+
void regex_replace(std::string &str) const;
1515
};
1616

1717
} //namespace rdf4cpp::regex

src/rdf4cpp/Literal.cpp

Lines changed: 15 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1972,22 +1972,13 @@ Literal Literal::as_regex_matches(regex::Regex const &pattern, storage::DynNodeS
19721972
}
19731973

19741974
Literal Literal::as_regex_matches(Literal const &pattern, Literal const &flags, storage::DynNodeStoragePtr node_storage) const noexcept {
1975-
if (this->null()) {
1976-
return Literal{};
1977-
}
1978-
1979-
if (!this->is_string_like() || !pattern.is_string_like() || !flags.is_string_like()) {
1980-
return Literal{};
1981-
}
1982-
1983-
if (pattern.datatype_eq<datatypes::rdf::LangString>() && this->language_tag() != pattern.language_tag()) {
1975+
if (this->null() || !this->is_string_like()) {
19841976
return Literal{};
19851977
}
19861978

19871979
auto const re = [&]() noexcept -> std::optional<regex::Regex> {
19881980
try {
1989-
auto const regex_flags = translate_regex_flags(flags.lexical_form());
1990-
return regex::Regex{pattern.lexical_form(), regex_flags};
1981+
return pattern.make_regex(flags);
19911982
} catch (std::runtime_error const &) {
19921983
return std::nullopt;
19931984
}
@@ -2001,6 +1992,17 @@ Literal Literal::as_regex_matches(Literal const &pattern, Literal const &flags,
20011992
return Literal::make_boolean(res, select_node_storage(node_storage));
20021993
}
20031994

1995+
regex::Regex Literal::make_regex(Literal const &flags) const {
1996+
if (this->null() || !this->datatype_eq<datatypes::xsd::String>()) {
1997+
throw std::runtime_error{"Literal cannot be converted for creating regex (null or not simple literal)"};
1998+
}
1999+
if (flags.null() || !flags.datatype_eq<datatypes::xsd::String>()) {
2000+
throw std::runtime_error{"Flags cannot be used for creating regex (null or not string-like)"};
2001+
}
2002+
auto const regex_flags = translate_regex_flags(flags.lexical_form());
2003+
return regex::Regex{this->lexical_form(), regex_flags};
2004+
}
2005+
20042006
Literal Literal::regex_replace(regex::RegexReplacer const &replacer, storage::DynNodeStoragePtr node_storage) const {
20052007
if (!this->is_string_like()) {
20062008
return Literal{};
@@ -2013,18 +2015,13 @@ Literal Literal::regex_replace(regex::RegexReplacer const &replacer, storage::Dy
20132015
}
20142016

20152017
Literal Literal::regex_replace(Literal const &pattern, Literal const &replacement, Literal const &flags, storage::DynNodeStoragePtr node_storage) const {
2016-
if (!this->is_string_like() || !pattern.is_string_like() || !replacement.is_string_like() || !flags.is_string_like()) {
2017-
return Literal{};
2018-
}
2019-
2020-
if (pattern.datatype_eq<datatypes::rdf::LangString>() && this->language_tag() != pattern.language_tag()) {
2018+
if (this->null() || !this->is_string_like()) {
20212019
return Literal{};
20222020
}
20232021

20242022
auto const re = [&]() noexcept -> std::optional<regex::Regex> {
20252023
try {
2026-
auto const regex_flags = translate_regex_flags(flags.lexical_form());
2027-
return regex::Regex{pattern.lexical_form(), regex_flags};
2024+
return pattern.make_regex(flags);
20282025
} catch (std::runtime_error const &) {
20292026
return std::nullopt;
20302027
}

src/rdf4cpp/Literal.hpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1174,6 +1174,13 @@ struct Literal : Node {
11741174
*/
11751175
[[nodiscard]] Literal as_regex_matches(Literal const &pattern, Literal const &flags = Literal::make_simple(""), storage::DynNodeStoragePtr node_storage = keep_node_storage) const noexcept;
11761176

1177+
/**
1178+
* @brief Creates a regex, whose pattern is the lexical form of the caller (this->lexical_form())
1179+
* @param flags regex flags to use for matching (https://www.w3.org/TR/xpath-functions/#flags)
1180+
* @return A regex object (rdf4cpp::regex::Regex)
1181+
*/
1182+
[[nodiscard]] regex::Regex make_regex(Literal const &flags = Literal::make_simple("")) const;
1183+
11771184
/**
11781185
* @see https://www.w3.org/TR/xpath-functions/#func-replace
11791186
*

src/rdf4cpp/regex/Regex.cpp

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,22 @@
1-
#include "Regex.hpp"
1+
#include <rdf4cpp/regex/Regex.hpp>
22
#include <rdf4cpp/regex/RegexImpl.hpp>
33
#include <rdf4cpp/regex/RegexReplacerImpl.hpp>
44

55
namespace rdf4cpp::regex {
66

7-
Regex::Regex(std::string_view regex, flag_type const flags) : impl{std::make_unique<Impl>(regex, flags)} {
7+
Regex::Regex(std::string_view regex, flag_type const flags) : impl_{std::make_shared<Impl const>(regex, flags)} {
88
}
99

10-
Regex::Regex(Regex &&other) noexcept = default;
11-
Regex &Regex::operator=(Regex &&other) noexcept = default;
12-
Regex::~Regex() noexcept = default;
13-
1410
bool Regex::regex_match(std::string_view const str) const noexcept {
15-
return this->impl->regex_match(str);
11+
return impl_->regex_match(str);
1612
}
1713

1814
bool Regex::regex_search(std::string_view const str) const noexcept {
19-
return this->impl->regex_search(str);
15+
return impl_->regex_search(str);
2016
}
2117

2218
RegexReplacer Regex::make_replacer(std::string_view const rewrite) const {
23-
return RegexReplacer{std::make_unique<RegexReplacer::Impl>(*this->impl, rewrite)};
19+
return RegexReplacer{std::make_shared<RegexReplacer::Impl>(impl_, rewrite)};
2420
}
2521

2622
} //namespace rdf4cpp::regex

src/rdf4cpp/regex/Regex.hpp

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ struct Regex {
1919
friend struct RegexReplacer;
2020

2121
struct Impl;
22-
std::unique_ptr<Impl> impl;
22+
std::shared_ptr<Impl const> impl_;
2323

2424
public:
2525
/**
@@ -32,11 +32,6 @@ struct Regex {
3232
*/
3333
explicit Regex(std::string_view regex, flag_type flags = flag_type::none());
3434

35-
Regex(Regex &&other) noexcept;
36-
Regex &operator=(Regex &&other) noexcept;
37-
38-
~Regex() noexcept;
39-
4035
/**
4136
* Similar to std::regex_match. Tries to match this regex against the
4237
* whole string.

src/rdf4cpp/regex/RegexReplacer.cpp

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,18 +3,11 @@
33

44
namespace rdf4cpp::regex {
55

6-
RegexReplacer::RegexReplacer(std::unique_ptr<Impl> &&impl) noexcept : impl{std::move(impl)} {
6+
RegexReplacer::RegexReplacer(std::shared_ptr<Impl> impl) noexcept : impl_{std::move(impl)} {
77
}
88

9-
RegexReplacer::RegexReplacer() noexcept = default;
10-
RegexReplacer::RegexReplacer(RegexReplacer &&other) noexcept = default;
11-
RegexReplacer &RegexReplacer::operator=(RegexReplacer &&other) noexcept = default;
12-
RegexReplacer::~RegexReplacer() noexcept = default;
13-
14-
void RegexReplacer::regex_replace(std::string &str) const noexcept {
15-
if (this->impl != nullptr) {
16-
this->impl->regex_replace(str);
17-
}
9+
void RegexReplacer::regex_replace(std::string &str) const {
10+
impl_->regex_replace(str);
1811
}
1912

2013
} //namespace rdf4cpp::regex

src/rdf4cpp/regex/RegexReplacer.hpp

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,15 +12,11 @@ struct RegexReplacer {
1212
friend struct Regex;
1313

1414
struct Impl;
15-
std::unique_ptr<Impl> impl;
15+
std::shared_ptr<Impl> impl_;
1616

17-
explicit RegexReplacer(std::unique_ptr<Impl> &&impl) noexcept;
18-
public:
19-
RegexReplacer() noexcept;
20-
RegexReplacer(RegexReplacer &&other) noexcept;
21-
RegexReplacer &operator=(RegexReplacer &&other) noexcept;
22-
~RegexReplacer() noexcept;
17+
explicit RegexReplacer(std::shared_ptr<Impl> impl) noexcept;
2318

19+
public:
2420
/**
2521
* Replaces all matches of the regex this replacer was constructed from in "str" with "rewrite" it
2622
* was constructed with.
@@ -42,7 +38,7 @@ struct RegexReplacer {
4238
* assert(s == "Hello 13th World);
4339
* @endcode
4440
*/
45-
void regex_replace(std::string &str) const noexcept;
41+
void regex_replace(std::string &str) const;
4642
};
4743

4844
} //namespace rdf4cpp::regex

tests/nodes/tests_Literal.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -729,7 +729,8 @@ TEST_CASE("Literal - misc functions") {
729729

730730
// check lang tag behaviour
731731
CHECK(Literal::make_lang_tagged("abcd", "en").as_regex_matches("b"_xsd_string).ebv());
732-
CHECK(Literal::make_lang_tagged("abcd", "en").as_regex_matches(Literal::make_lang_tagged("b", "en")).ebv());
732+
// pattern and flags should be simple literals (xsd:string)
733+
CHECK(Literal::make_lang_tagged("abcd", "en").as_regex_matches(Literal::make_lang_tagged("b", "en")).null());
733734
CHECK(Literal::make_lang_tagged("abcd", "en").as_regex_matches(Literal::make_lang_tagged("b", "fr")).null());
734735

735736
CHECK(!Literal::make_simple("abc\ndef\ngh").as_regex_matches("^def$"_xsd_string).ebv());
@@ -767,7 +768,8 @@ TEST_CASE("Literal - misc functions") {
767768

768769
// check lang tag behaviour
769770
CHECK_EQ(Literal::make_lang_tagged("abcd", "en").regex_replace("b"_xsd_string, "Z"_xsd_string), Literal::make_lang_tagged("aZcd", "en"));
770-
CHECK_EQ(Literal::make_lang_tagged("abcd", "en").regex_replace(Literal::make_lang_tagged("b", "en"), "Z"_xsd_string), Literal::make_lang_tagged("aZcd", "en"));
771+
// pattern and flag should be simple literals (xsd:string)
772+
CHECK(Literal::make_lang_tagged("abcd", "en").regex_replace(Literal::make_lang_tagged("b", "en"), "Z"_xsd_string).null());
771773
CHECK(Literal::make_lang_tagged("abcd", "en").regex_replace(Literal::make_lang_tagged("b", "fr"), "Z"_xsd_string).null());
772774

773775
CHECK(("Hello 1 World"_xsd_string).regex_replace("[0-9]"_xsd_string, "Hello \\\\hgfhf World"_xsd_string) == "Hello Hello \\hgfhf World World"_xsd_string);

tests/util/tests_Regex.cpp

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,9 @@ using namespace rdf4cpp::regex;
88
TEST_SUITE("regex") {
99
TEST_CASE("replacement translation") {
1010
Regex const r{"[0-9]"};
11-
RegexReplacer repl_dummy;
1211

1312
SUBCASE("no escape") {
14-
CHECK_THROWS(repl_dummy = r.make_replacer("$"));
13+
CHECK_THROWS((void) r.make_replacer("$"));
1514

1615
{
1716
std::string s = "Hello 99 World";
@@ -35,7 +34,7 @@ TEST_SUITE("regex") {
3534
}
3635

3736
SUBCASE("2 escape") {
38-
CHECK_THROWS(repl_dummy = r.make_replacer(R"(\\$)"));
37+
CHECK_THROWS((void) r.make_replacer(R"(\\$)"));
3938

4039
{
4140
std::string s = "Hello 99 World";
@@ -59,7 +58,7 @@ TEST_SUITE("regex") {
5958
}
6059

6160
SUBCASE("4 escape") {
62-
CHECK_THROWS(repl_dummy = r.make_replacer(R"(\\\\$)"));
61+
CHECK_THROWS((void) r.make_replacer(R"(\\\\$)"));
6362

6463
{
6564
std::string s = "Hello 99 World";

0 commit comments

Comments
 (0)