libzypp  17.28.8
StringV.cc
Go to the documentation of this file.
1 /*---------------------------------------------------------------------\
2 | ____ _ __ __ ___ |
3 | |__ / \ / / . \ . \ |
4 | / / \ V /| _/ _/ |
5 | / /__ | | | | | | |
6 | /_____||_| |_| |_| |
7 | |
8 \---------------------------------------------------------------------*/
11 #include <iostream>
12 #include <zypp-core/base/StringV.h>
13 
15 namespace zypp
16 {
17  namespace strv
18  {
19  namespace detail
20  {
26  unsigned _splitSimple( std::string_view line_r, WordConsumer && fnc_r )
27  {
28  // callback stats
29  unsigned fncCall = 0;
30 
31  // NOTE: line_r is not null-terminated!
32  const char *const eol = line_r.data() + line_r.size(); // the '\0'
33  const char * searchfrom = line_r.data(); // start of the next search (moves with each cycle!)
34 
35  // Empty sep: split at /[BLANK,TAB]+/ and report no-empty words
36  auto isSep = []( char ch )->bool { return ch == ' '|| ch == '\t'; };
37 
38  auto skipSep = [eol,&isSep]( const char *& ptr )->bool {
39  while ( ptr < eol && isSep( *ptr ) )
40  ++ptr;
41  return ptr < eol; // whether we ended up at a new wordstart
42  };
43 
44  auto skipWord = [eol,&isSep]( const char *& ptr )->void {
45  while ( ptr < eol && ! isSep( *ptr ) )
46  ++ptr;
47  };
48 
49  // For the 'last' CB argument: we must remember a word
50  // until we know whether another one is following
51  std::string_view word;
52 
53  while ( skipSep( searchfrom ) ) {
54  const char * wordstart = searchfrom;
55  // Report a previous word found
56  if ( ! word.empty() ) {
57  if ( fnc_r ) {
58  if ( ! fnc_r( word, fncCall, false/*more to come*/ ) ) {
59  // Stop searching for further matches. Final report will
60  // be the remaining line (right trimmed)
61  const char * wordend = eol;
62  while ( isSep( *(wordend-1) ) ) // noSep at wordstart stops loop
63  --wordend;
64  word = std::string_view( wordstart, wordend-wordstart );
65  ++fncCall;
66  break;
67  }
68  }
69  ++fncCall;
70  }
71  // remember new word
72  ++searchfrom;
73  skipWord( searchfrom );
74  word = std::string_view( wordstart, searchfrom-wordstart );
75  }
76 
77  // finally report the last word
78  if ( ! word.empty() ) {
79  if ( fnc_r ) {
80  fnc_r( word, fncCall, true/*last*/ );
81  }
82  ++fncCall;
83  }
84 
85  return fncCall;
86  }
87  } // namespace detail
88 
89  unsigned detail::_split( std::string_view line_r, std::string_view sep_r, Trim trim_r, WordConsumer && fnc_r )
90  {
91  if ( sep_r.empty() )
92  return _splitSimple( line_r, std::move( fnc_r ) );
93 
94  // callback stats
95  bool fncStop = false;
96  unsigned fncCall = 0;
97 
99  size_type wordstart = 0; // start of the next string to be reported
100  size_type searchfrom = 0; // start of the next search for a separator
101 
102  do { // report lhs word of separator matches...
103  searchfrom = line_r.find( sep_r, searchfrom );
104  if ( fncStop || searchfrom == line_r.npos ) {
105  break;
106  }
107 
108  // Report lhs word of the match and advance...
109  if ( fnc_r ) {
110  if ( ! fnc_r( trim( line_r.substr(wordstart,searchfrom-wordstart), trim_r ), fncCall, false/*more to come*/ ) )
111  fncStop= true; // stop searching for further matches
112  }
113  ++fncCall;
114 
115  // Next wordstart is behind the separator match.
116  searchfrom += sep_r.size();
117  wordstart = searchfrom;
118  } while( wordstart < line_r.size() );
119 
120  // finally report rhs word of the last separator match (or no match)
121  if ( fnc_r ) {
122  if ( wordstart < line_r.size() )
123  fnc_r( trim( line_r.substr(wordstart,line_r.size()-wordstart), trim_r ), fncCall, true/*last*/ );
124  else // a final match at $ so a final empty word reported (no trim needed)
125  fnc_r( std::string_view( line_r.data()+line_r.size(), 0 ), fncCall, true/*last*/ );
126  }
127  ++fncCall;
128  return fncCall;
129  }
130 
131  unsigned detail::_splitRx( const std::string & line_r, const regex & rx_r, WordConsumer && fnc_r )
132  {
133  // callback stats
134  bool fncStop = false;
135  unsigned fncCall = 0;
136 
137  // report lhs word of separator matches...
138  const char *const eol = line_r.data() + line_r.size(); // the '\0'
139  bool trailingNL = line_r.size() && *(eol-1) == '\n'; // line ends with NL
140  const char * wordstart = line_r.data(); // start of the next string to be reported
141  const char * searchfrom = line_r.data(); // start of the next search for a separator (moves with each cycle!)
142 
143  // Whether to match the ^ at beginning of the line or after an \n:
144  auto matchAtBOL = [&]() {
145  return searchfrom == line_r.data() || *(searchfrom-1) == '\n' ? regex::none : regex::not_bol;
146  };
147  do { // report lhs word of separator matches...
148  smatch match;
149  if ( fncStop || ! rx_r.matches( searchfrom, match, matchAtBOL() ) ) {
150  break;
151  }
152  if ( trailingNL && searchfrom+match.begin(0) == eol )
153  break; // don't report matches behind a trailing NL
154 
155  if ( match.end(0) == 0 && searchfrom == wordstart && searchfrom != line_r.data() ) {
156  // An empty(!) separator found at wordstart is ignored unless we're at the very beginning.
157  // If searchfrom == wordstart we just skipped over a not-empty separator. If wordstart is
158  // not part of a 2nd not-empty separator, we want the next separator to it's right.
159  // Example: Rx:"b*" Str:"0b2" - at pos 2 Rx matches empty; the previous cycle found 'b' and reported the '0'.
160  ++searchfrom;
161  } else {
162  // Report lhs word of the match and advance...
163  if ( fnc_r ) {
164  if ( ! fnc_r( std::string_view( wordstart, searchfrom+match.begin(0) - wordstart ), fncCall, false/*more to come*/ ) )
165  fncStop= true; // stop searching for further matches
166  }
167  ++fncCall;
168  // Next wordstart is behind the separator match.
169  // Next searchfrom also, but advances at least by 1.
170  wordstart = searchfrom+match.end(0);
171  searchfrom += match.end(0) ? match.end(0) : 1;
172  }
173  } while ( searchfrom <= eol ); // incl. '== eol' as there might be an (empty) match at $
174 
175  // finally report rhs word of the last separator match (or no match)
176  if ( fnc_r ) {
177  if ( wordstart < eol )
178  fnc_r( std::string_view( wordstart, eol-wordstart ), fncCall, true/*last*/ );
179  else // a final match at $ so a final empty word reported
180  fnc_r( std::string_view( eol, 0 ), fncCall, true/*last*/ );
181  }
182  ++fncCall;
183  return fncCall;
184  }
185 
186  } // namespace strv
187 } // namespace zypp
SolvableIdType size_type
Definition: PoolMember.h:126
Trim
To define how to trim.
Definition: String.h:496
std::string trim(const std::string &s, const Trim trim_r)
Definition: String.cc:223
unsigned _splitSimple(std::string_view line_r, WordConsumer &&fnc_r)
split working horse for empty sep_r case.
Definition: StringV.cc:26
Easy-to use interface to the ZYPP dependency resolver.
Definition: CodePitfalls.doc:2