libzypp: zypp-core/base/StringV.cc Source File

libzypp 17.36.6

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, const 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 unsigned detail::_splitRx( std::string_view line_r, const regex & rx_r, const 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 its 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
zypp::str::trim
std::string trim(const std::string &s, const Trim trim_r)
Definition String.cc:224
zypp::strv::detail
Definition StringV.cc:20
zypp::strv::detail::_splitSimple
unsigned _splitSimple(std::string_view line_r, const WordConsumer &fnc_r)
split working horse for empty sep_r case.
Definition StringV.cc:26
zypp::strv
Definition StringV.cc:18
zypp
Easy-to use interface to the ZYPP dependency resolver.
Definition Application.cc:20
StringV.h