regex-top-matcher.cpp
Go to the documentation of this file.
1 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2 /*
3  * Copyright (c) 2013-2023 Regents of the University of California.
4  *
5  * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
6  *
7  * ndn-cxx library is free software: you can redistribute it and/or modify it under the
8  * terms of the GNU Lesser General Public License as published by the Free Software
9  * Foundation, either version 3 of the License, or (at your option) any later version.
10  *
11  * ndn-cxx library is distributed in the hope that it will be useful, but WITHOUT ANY
12  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
13  * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
14  *
15  * You should have received copies of the GNU General Public License and GNU Lesser
16  * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see
17  * <http://www.gnu.org/licenses/>.
18  *
19  * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
20  *
21  * @author Yingdi Yu <http://irl.cs.ucla.edu/~yingdi/>
22  */
23 
25 
28 
29 #include <boost/lexical_cast.hpp>
30 
31 namespace ndn {
32 
33 RegexTopMatcher::RegexTopMatcher(const std::string& expr, const std::string& expand)
34  : RegexMatcher(expr, EXPR_TOP)
35  , m_expand(expand)
36  , m_isSecondaryUsed(false)
37 {
38  m_primaryBackrefManager = make_shared<RegexBackrefManager>();
39  m_secondaryBackrefManager = make_shared<RegexBackrefManager>();
40  compile();
41 }
42 
43 void
44 RegexTopMatcher::compile()
45 {
46  std::string expr = m_expr;
47 
48  if ('$' != expr[expr.size() - 1])
49  expr = expr + "<.*>*";
50  else
51  expr = expr.substr(0, expr.size() - 1);
52 
53  if ('^' != expr[0]) {
54  m_secondaryMatcher = make_shared<RegexPatternListMatcher>("<.*>*" + expr,
55  m_secondaryBackrefManager);
56  }
57  else {
58  expr = expr.substr(1, expr.size() - 1);
59  }
60 
61  m_primaryMatcher = make_shared<RegexPatternListMatcher>(expr, m_primaryBackrefManager);
62 }
63 
64 bool
66 {
67  m_isSecondaryUsed = false;
68 
69  m_matchResult.clear();
70 
71  if (m_primaryMatcher->match(name, 0, name.size())) {
72  m_matchResult = m_primaryMatcher->getMatchResult();
73  return true;
74  }
75  else {
76  if (m_secondaryMatcher != nullptr && m_secondaryMatcher->match(name, 0, name.size())) {
77  m_matchResult = m_secondaryMatcher->getMatchResult();
78  m_isSecondaryUsed = true;
79  return true;
80  }
81  return false;
82  }
83 }
84 
85 bool
86 RegexTopMatcher::match(const Name& name, size_t, size_t)
87 {
88  return match(name);
89 }
90 
91 Name
92 RegexTopMatcher::expand(const std::string& expandStr)
93 {
94  auto backrefManager = m_isSecondaryUsed ? m_secondaryBackrefManager : m_primaryBackrefManager;
95  size_t backrefNo = backrefManager->size();
96 
97  std::string expand;
98  if (!expandStr.empty())
99  expand = expandStr;
100  else
101  expand = m_expand;
102 
103  Name result;
104  size_t offset = 0;
105  while (offset < expand.size()) {
106  std::string item = getItemFromExpand(expand, offset);
107  if (item[0] == '<') {
108  result.append(item.substr(1, item.size() - 2));
109  }
110  if (item[0] == '\\') {
111  size_t index = boost::lexical_cast<size_t>(item.substr(1, item.size() - 1));
112  if (index == 0) {
113  for (const auto& i : m_matchResult)
114  result.append(i);
115  }
116  else if (index <= backrefNo) {
117  for (const auto& i : backrefManager->getBackref(index - 1)->getMatchResult())
118  result.append(i);
119  }
120  else
121  NDN_THROW(Error("Exceeded the range of back reference"));
122  }
123  }
124 
125  return result;
126 }
127 
128 std::string
129 RegexTopMatcher::getItemFromExpand(const std::string& expand, size_t& offset)
130 {
131  size_t begin = offset;
132 
133  if (expand[offset] == '\\') {
134  offset++;
135  if (offset >= expand.size())
136  NDN_THROW(Error("Wrong format of expand string"));
137 
138  while (expand[offset] <= '9' and expand[offset] >= '0') {
139  offset++;
140  if (offset > expand.size())
141  NDN_THROW(Error("Wrong format of expand string"));
142  }
143  if (offset > begin + 1)
144  return expand.substr(begin, offset - begin);
145  else
146  NDN_THROW(Error("Wrong format of expand string"));
147  }
148  else if (expand[offset] == '<') {
149  offset++;
150  if (offset >= expand.size())
151  NDN_THROW(Error("Wrong format of expand string"));
152 
153  size_t left = 1;
154  size_t right = 0;
155  while (right < left) {
156  if (expand[offset] == '<')
157  left++;
158  if (expand[offset] == '>')
159  right++;
160  offset++;
161  if (offset >= expand.size())
162  NDN_THROW(Error("Wrong format of expand string"));
163  }
164  return expand.substr(begin, offset - begin);
165  }
166  else
167  NDN_THROW(Error("Wrong format of expand string"));
168 }
169 
170 shared_ptr<RegexTopMatcher>
171 RegexTopMatcher::fromName(const Name& name, bool hasAnchor)
172 {
173  std::string regexStr("^");
174 
175  for (const auto& i : name) {
176  regexStr.append("<");
177  regexStr.append(convertSpecialChar(i.toUri()));
178  regexStr.append(">");
179  }
180 
181  if (hasAnchor)
182  regexStr.append("$");
183 
184  return make_shared<RegexTopMatcher>(regexStr);
185 }
186 
187 std::string
188 RegexTopMatcher::convertSpecialChar(const std::string& str)
189 {
190  std::string newStr;
191 
192  for (size_t i = 0; i < str.size(); i++) {
193  char c = str[i];
194  switch (c) {
195  case '.':
196  case '[':
197  case '{':
198  case '}':
199  case '(':
200  case ')':
201  case '\\':
202  case '*':
203  case '+':
204  case '?':
205  case '|':
206  case '^':
207  case '$':
208  newStr.push_back('\\');
209  [[fallthrough]];
210  default:
211  newStr.push_back(c);
212  break;
213  }
214  }
215 
216  return newStr;
217 }
218 
219 } // namespace ndn
Represents an absolute name.
Definition: name.hpp:45
size_t size() const noexcept
Returns the number of components.
Definition: name.hpp:180
Name & append(const Component &component)
Append a name component.
Definition: name.hpp:308
std::vector< name::Component > m_matchResult
const std::string m_expr
static shared_ptr< RegexTopMatcher > fromName(const Name &name, bool hasAnchor=false)
bool match(const Name &name)
virtual Name expand(const std::string &expand="")
RegexTopMatcher(const std::string &expr, const std::string &expand="")
#define NDN_THROW(e)
Definition: exception.hpp:56
Definition: data.cpp:25