libzypp 17.31.23
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
15namespace 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
98 using size_type = std::string_view::size_type;
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#if LEGACY(1722)
132 unsigned detail::_splitRx( const std::string & line_r, const regex & rx_r, WordConsumer && fnc_r )
133 { return _splitRx( std::string_view(line_r), rx_r, std::move(fnc_r) ); }
134#endif
135 unsigned detail::_splitRx( std::string_view line_r, const regex & rx_r, WordConsumer && fnc_r )
136 {
137 // callback stats
138 bool fncStop = false;
139 unsigned fncCall = 0;
140
141 // report lhs word of separator matches...
142 const char *const eol = line_r.data() + line_r.size(); // the '\0'
143 bool trailingNL = line_r.size() && *(eol-1) == '\n'; // line ends with NL
144 const char * wordstart = line_r.data(); // start of the next string to be reported
145 const char * searchfrom = line_r.data(); // start of the next search for a separator (moves with each cycle!)
146
147 // Whether to match the ^ at beginning of the line or after an \n:
148 auto matchAtBOL = [&]() {
149 return searchfrom == line_r.data() || *(searchfrom-1) == '\n' ? regex::none : regex::not_bol;
150 };
151 do { // report lhs word of separator matches...
152 smatch match;
153 if ( fncStop || ! rx_r.matches( searchfrom, match, matchAtBOL() ) ) {
154 break;
155 }
156 if ( trailingNL && searchfrom+match.begin(0) == eol )
157 break; // don't report matches behind a trailing NL
158
159 if ( match.end(0) == 0 && searchfrom == wordstart && searchfrom != line_r.data() ) {
160 // An empty(!) separator found at wordstart is ignored unless we're at the very beginning.
161 // If searchfrom == wordstart we just skipped over a not-empty separator. If wordstart is
162 // not part of a 2nd not-empty separator, we want the next separator to its right.
163 // Example: Rx:"b*" Str:"0b2" - at pos 2 Rx matches empty; the previous cycle found 'b' and reported the '0'.
164 ++searchfrom;
165 } else {
166 // Report lhs word of the match and advance...
167 if ( fnc_r ) {
168 if ( ! fnc_r( std::string_view( wordstart, searchfrom+match.begin(0) - wordstart ), fncCall, false/*more to come*/ ) )
169 fncStop= true; // stop searching for further matches
170 }
171 ++fncCall;
172 // Next wordstart is behind the separator match.
173 // Next searchfrom also, but advances at least by 1.
174 wordstart = searchfrom+match.end(0);
175 searchfrom += match.end(0) ? match.end(0) : 1;
176 }
177 } while ( searchfrom <= eol ); // incl. '== eol' as there might be an (empty) match at $
178
179 // finally report rhs word of the last separator match (or no match)
180 if ( fnc_r ) {
181 if ( wordstart < eol )
182 fnc_r( std::string_view( wordstart, eol-wordstart ), fncCall, true/*last*/ );
183 else // a final match at $ so a final empty word reported
184 fnc_r( std::string_view( eol, 0 ), fncCall, true/*last*/ );
185 }
186 ++fncCall;
187 return fncCall;
188 }
189
190 } // namespace strv
191} // namespace zypp
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