String routines to complement <string> && <cstring>:
string_tool.cpp
Go to the documentation of this file.
1 // string_tool.cpp (C) 2012 adolfo@di-mare.com
2 
3 /** \file string_tool.cpp
4  \brief Implementación de \c string_tool.cpp.
5  \author Adolfo Di Mare <adolfo@di-mare.com>
6  \date 2012
7 */
8 
9 #include <cctype>
10 #include "string_tool.h"
11 
12 /** Convierte a minúscula todas las letras de \c line.
13  - Solo funciona para letras ASCII.
14 
15  \dontinclude string_tool_test.cpp
16  \skipline test::tolower()
17  \until }}
18 */
19 void tolower( std::string& line ) {
20  std::string::iterator it = line.begin();
21  while ( it!=line.end() ) {
22  *it = tolower(*it);
23  ++it;
24  }
25 }
26 
27 /** Retorna la letra sin acento que corresponde a \c ch.
28  - Funciona para letras del alfabeto ISO-8859-1 Latin No.1.
29  - Funciona para letras del alfabeto Windows-1252 (Latin).
30  - Modifica letras cuyo código está en el rango [192..255].
31  - Por ejemplo: <code>assertTrue( 'n' == removeAccented('ñ') )</code>
32  - \see http://en.wikipedia.org/wiki/ISO/IEC_8859-1
33  - \see https://en.wikipedia.org/wiki/Windows-1252
34 
35  \dontinclude string_tool_test.cpp
36  \skipline test::removeAccented(char)
37  \until }}
38 */
39 char removeAccented( char ch ) {
40  const char*
41  // A_TILDE_64
42  tr = A_SIMPLE_64;
43 
44  unsigned char uch = ch;
45  if ( uch >=192 ) {
46  uch = tr[ uch-192 ];
47  }
48  // http://stackoverflow.com/questions/14094621/
49 
50  return char(uch);
51 }
52 
53 /** Convierte todas las letras con acento en letras sin accento.
54  - Funciona para letras del alfabeto ISO-8859-1 Latin No.1.
55  - Funciona para letras del alfabeto Windows-1252 (Latin).
56  - Modifica letras cuyo código está en el rango [192..255].
57  - \see http://en.wikipedia.org/wiki/ISO/IEC_8859-1
58  - \see https://en.wikipedia.org/wiki/Windows-1252
59 
60  \dontinclude string_tool_test.cpp
61  \skipline test::removeAccented(char*)
62  \until }}
63 */
64 const char* removeAccented( char* str ) {
65  char *p = str;
66  while ( (*p)!=0 ) {
67  #if 1
68  const char*
69  // A_TILDE_64
70  tr = A_SIMPLE_64;
71  unsigned char ch = (*p);
72  if ( ch >=192 ) {
73  (*p) = tr[ ch-192 ];
74  }
75  #else
76  *p = removeAccented(*p) ;
77  #endif // 0
78  ++p;
79  // http://stackoverflow.com/questions/14094621/
80  }
81  return str;
82 }
83 
84 /** Convierte todas las letras con acento en letras sin accento.
85  - Funciona para letras del alfabeto ISO-8859-1 Latin No.1.
86  - Funciona para letras del alfabeto Windows-1252 (Latin).
87  - Modifica letras cuyo código está en el rango [192..255].
88  - \see http://en.wikipedia.org/wiki/ISO/IEC_8859-1
89  - \see https://en.wikipedia.org/wiki/Windows-1252
90 
91  \dontinclude string_tool_test.cpp
92  \skipline test::removeAccented(string)
93  \until }}
94 */
95 const std::string& removeAccented( std::string& str ) {
96  std::string::iterator p = str.begin();
97  while ( p!=str.end() ) {
98  #if 1
99  const char*
100  // A_TILDE_64
101  tr = A_SIMPLE_64;
102  unsigned char ch = (*p);
103  if ( ch >=192 ) {
104  (*p) = tr[ ch-192 ];
105  }
106  #else
107  *p = removeAccented(*p) ;
108  #endif // 0
109  ++p;
110  // http://stackoverflow.com/questions/14094621/
111  }
112  return str;
113 }
114 
115 /** Elimina comillas ['] ["] del principio o final de 'word'.
116 
117  \dontinclude string_tool_test.cpp
118  \skipline test::trimQuote(string)
119  \until }}
120 */
121 void trimQuote( std::string& word ) {
122  unsigned len = word.length();
123  if ( len == 0 ) { return; }
124  --len;
125  if ( word[len]=='\"' || word[len]=='\'' ) { --len; }
126 
127  unsigned from=0;
128  if ( word[0]=='\"' || word[0]=='\'' ) { ++from; --len; }
129 
130  word = word.substr( from, len );
131 }
132 
133 /** Regresa \c true si todos los caracteres de \c line son alfabéticos.
134  - Usa la rutina estándar \c isalpha().
135 
136  \dontinclude string_tool_test.cpp
137  \skipline test::isalpha()
138  \until }}
139 */
140 bool isalpha( const std::string& line ) {
141  std::string::const_iterator it = line.begin();
142  while ( it!=line.end() ) {
143  if ( !isalpha(*it) ) { return false; }
144  ++it;
145  }
146  return true;
147 }
148 
149 /** Retorna \c true si todos las caracteres en \c word son blancos.
150  - Usa la rutina estándar \c isspace() para determinar si
151  un caracter es blanco.
152 
153  \dontinclude string_tool_test.cpp
154  \skipline test::is_blank()
155  \until }}
156 */
157 bool is_blank( const std::string& word ) {
158  std::string::const_iterator it = word.begin();
159  while ( isspace(*it) ) {
160  it++;
161  }
162  return (it == word.end() );
163 }
164 
165 /** Verifica si \c suffix es un sufijo de \c str.
166  - Ignora las diferencias entre mayúsculas y minúsculas.
167 
168  \dontinclude string_tool_test.cpp
169  \skipline test::issuffix()
170  \until }}
171 */
172 bool issuffix( const char* str, const char* suffix ) {
173  { // la hilera nula siempre es sufijo de cualquier hilera
174  bool check_null = (suffix==0);
175  if (!check_null) { check_null = (*suffix==0); }
176  if (check_null) { return true; }
177  }
178  { // nadie es sufijo de la hilera nula
179  bool check_null = (str==0);
180  if (!check_null) { check_null = (*str==0); }
181  if (check_null) { return false; }
182  }
183  // assert( (str!=0) && (suffix!=0) );
184 
185  unsigned str_len = strlen( str );
186  unsigned suffix_len = strlen( suffix );
187 
188  if ( str_len < suffix_len ) { return false; }
189 
190  const char *p = str+str_len;
191  const char *q = suffix+suffix_len;
192  do {
193  --p; --q;
194  if ( tolower(*p) != tolower(*q) ) { return false; }
195  } while ( q!=suffix );
196 
197  return true; // assert( q==suffix );
198 }
199 
200 /** Retorna la cantidad de dígitos consecutivos a partir de \c str[i].
201  - Usa la rutina estándar \c isdigit().
202  - Retorna \c 0 (cero) si no hay dígitos a partir de \c str[i].
203  - Retorna \c string::npos si hay errores.
204 
205  \dontinclude string_tool_test.cpp
206  \skipline test::digitCount()
207  \until }}
208 */
209 unsigned digitCount( const std::string& str , unsigned i ) {
210  unsigned N=str.length();
211  if ( (i>=N) ) { return std::string::npos; }
212  unsigned n=0;
213  while ( i<N ) {
214  if ( !isdigit(str[i]) ) { return n; }
215  ++i; ++n;
216  }
217  return n;
218 }
219 
220 /** Retorna la cantidad de letras consecutivas a partir de 'str[i]'.
221  - Usa la rutina estándar \c isalpha().
222  - Retorna \c 0 (cero) si no hay letras a partir de 'str[i]'.
223  - Retorna \c string::npos si hay errores.
224 
225  \dontinclude string_tool_test.cpp
226  \skipline test::alphaCount()
227  \until }}
228 */
229 unsigned alphaCount( const std::string& str , unsigned i ) {
230  unsigned N=str.length();
231  if ( (i>=N) ) { return std::string::npos; }
232  unsigned n=0;
233  while ( i<N ) {
234  if ( !isalpha(str[i]) ) { return n; }
235  ++i; ++n;
236  }
237  return n;
238 }
239 
240 /** Retorna el número que está al final de \c str.
241  - Retorna \c std::string::npos si el sufijo de 'str' no es numérico.
242  - Nunca retorna valores negativos (pues siempre ignora '-').
243 
244  \dontinclude string_tool_test.cpp
245  \skipline test::number_suffix()
246  \until }}
247 */
248 unsigned number_suffix( const std::string& str ) {
249  if ( str.empty() ) { return std::string::npos; }
250  unsigned i = str.size()-1;
251  if ( !isdigit(str[i]) ) { return std::string::npos; }
252 
253  unsigned n = 0;
254  unsigned mult = 1;
255  for (;;) {
256  char ch = str[i];
257  if ( !isdigit(ch) ) { break;}
258  n += (ch-'0')*mult;
259  if ( i==0 ) { break; }
260  --i; mult *= 10;
261  }
262  return n;
263 }
264 
265 
266 /** Convierte 's' un número entero sin signo.
267  - Solo convierte el prefijo numérico 'str'.
268  - Ignora el signo si está presente.
269 
270  \dontinclude string_tool_test.cpp
271  \skipline test::str2uint()
272  \until }}
273 */
274 unsigned str2uint( const std::string& str ) {
275  unsigned i=0; // comienza desde el principio
276  unsigned N=str.length();
277  while ( i<N ) {
278  if ( isspace(str[i]) ) { ++i; }
279  else { break; }
280  }
281  if ( i==N ) { return 0; }
282  if ( str[i]=='-' || str[i]=='+' ) { ++i; }
283  if ( i==N ) { return 0; }
284 
285  // periodo multiplicador
286  unsigned n=0, nMult;
287  while ( i<N ) {
288  if ( !isdigit(str[i]) ) { break; }
289  nMult = 10 * n;
290  n = nMult + (str[i]-'0');
291  ++i;
292  }
293  return n;
294 }
295 
296 
297 /** Retorna la hilera que contiene los últimos 'width' dígitos de 'N'.
298  - Rellena con ceros al principio si hace falta.
299 
300  \dontinclude string_tool_test.cpp
301  \skipline test::tostring()
302  \until }}
303 */
304 std::string tostring( unsigned N, unsigned width ) {
305  if ( width==0 ) { return std::string(); }
306  // -> http://stackoverflow.com/questions/26587110
307  std::string ret; ret.resize( width );
308  unsigned i=width;
309  do {
310  --i;
311  ret[i]= N%10+'0';
312  N /= 10;
313  } while (i>0);
314  return ret;
315 }
316 
317 /** Almacena en 'str' los últimos 'width' dígitos de 'N'.
318  - Rellena con ceros al principio si hace falta.
319  - Graba el fin de hilera '\0' en 'str[width]'.
320 
321  \dontinclude string_tool_test.cpp
322  \skipline test::tostring_char()
323  \until }}
324 */
325 void tostring( unsigned N, unsigned width, char *str ) {
326  if ( width==0 ) { *str = 0; return; }
327  unsigned i=width;
328  do {
329  --i;
330  str[i]= N%10+'0';
331  N /= 10;
332  } while (i>0);
333  *(str+width)=0;
334 }
335 
336 
337 /** Separa las palabras de 'renglon' y las deja en la lista 'L'.
338  Usa los caracteres 'delimiters' como separadores.
339  Se brinca los espacios en blanco.
340  El contenido anterior del contenedor 'L' siempre queda eliminado.
341  \pre Siempre es necesario que el blanco ' ' aparezca como
342  caracter delimitador en \c delimiters.
343 
344  \dontinclude string_tool_test.cpp
345  \skipline test::tokens()
346  \until }}
347 */
348 void tokens( const std::string& renglon, std::list<std::string>& L, const char* delimiters ) {
349  // Implementación de \c tokens() que usa \c find_first_of().
350  L.clear();
351  // using namespace std;
352  // http://cplusplus.com/faq/sequences/strings/split/#string-find_first_of
353  size_t current = 0;
354  size_t next = renglon.find_first_of( delimiters, current );
355  while (next != std::string::npos) {
356  if ( ' ' == renglon[current] ) {
357  current = next+1; // skip blanks
358  }
359  else if ( current==next ) {
360  L.push_back( renglon.substr(current,(1) ) );
361  // std::cout <<"<"<< renglon.substr(current,(1) ) << ">";
362  current = next+1;
363  }
364  else {
365  L.push_back( renglon.substr(current,(next-current) ) );
366  // std::cout <<"<"<< renglon.substr(current,(next-current) ) << ">";
367  current = next;
368  }
369  next = renglon.find_first_of( delimiters, current );
370  }
371  if ( current < renglon.size() ) {
372  L.push_back( renglon.substr(current,(std::string::npos) ) );
373  // std::cout << renglon.substr(current,(std::string::npos) ) << " !!!\n";
374  }
375  // http://www.cplusplus.com/reference/string/string/find_first_of/
376 }
377 
378 /** Deletes 'len' chars from 'str' starting at index 'from'.
379 
380  \dontinclude string_tool_test.cpp
381  \skipline test::strdel()
382  \until }}
383 */
384 char *strdel(char *str, size_t from, size_t len) {
385  size_t slen = strlen(str);
386  // if (len==0) { return str; }
387  if (from >= slen) { return str; } // out of bounce
388  if (from+len > slen) { len = slen-from; }
389  memmove( str+(from), str+(from+len), slen-(from+len)+1 );
390  return str;
391 }
392 /*
393  (p+2,3)
394  01...567890123456
395  16 -> slen
396  13 -> slen-3
397  5 -> 2+3 -> from+len
398 
399  13 -> 16-5+1 -> slen-(from+len)+1
400 */
401 /** Deletes 'len' chars from the start of 'str'.
402 
403  \dontinclude string_tool_test.cpp
404  \skipline test::strdel2()
405  \until }}
406 */
407 char *strdel2(char *str, size_t len) {
408  size_t slen = strlen(str);
409  // if (len==0) { return str; }
410  if (len > slen) { len = slen; }
411  memmove( str, str+len, slen-len+1 );
412  return str;
413 }
414 /*
415  Implementation copied from strdel() replacing ing 'from' by 0.
416 */
417 
418 
419 // EOF: string_tool.cpp
str2uint
unsigned str2uint(const std::string &str)
Convierte 's' un número entero sin signo.
Definition: string_tool.cpp:274
issuffix
bool issuffix(const char *str, const char *suffix)
Verifica si suffix es un sufijo de str.
Definition: string_tool.cpp:172
alphaCount
unsigned alphaCount(const std::string &str, unsigned i)
Retorna la cantidad de letras consecutivas a partir de 'str[i]'.
Definition: string_tool.cpp:229
is_blank
bool is_blank(const std::string &word)
Retorna true si todos las caracteres en word son blancos.
Definition: string_tool.cpp:157
string_tool.h
Rutinas de hileras que complementan <string> y <cstring>.
number_suffix
unsigned number_suffix(const std::string &str)
Retorna el número que está al final de str.
Definition: string_tool.cpp:248
strdel2
char * strdel2(char *str, size_t len)
Deletes 'len' chars from the start of 'str'.
Definition: string_tool.cpp:407
tostring
std::string tostring(unsigned N, unsigned width)
Retorna la hilera que contiene los últimos 'width' dígitos de 'N'.
Definition: string_tool.cpp:304
tolower
void tolower(std::string &line)
Convierte a minúscula todas las letras de line.
Definition: string_tool.cpp:19
removeAccented
char removeAccented(char ch)
Retorna la letra sin acento que corresponde a ch.
Definition: string_tool.cpp:39
isalpha
bool isalpha(const std::string &line)
Regresa true si todos los caracteres de line son alfabéticos.
Definition: string_tool.cpp:140
A_SIMPLE_64
#define A_SIMPLE_64
Definition: string_tool.h:55
tokens
void tokens(const std::string &renglon, std::list< std::string > &L, const char *delimiters)
Separa las palabras de 'renglon' y las deja en la lista 'L'.
Definition: string_tool.cpp:348
strdel
char * strdel(char *str, size_t from, size_t len)
Deletes 'len' chars from 'str' starting at index 'from'.
Definition: string_tool.cpp:384
digitCount
unsigned digitCount(const std::string &str, unsigned i)
Retorna la cantidad de dígitos consecutivos a partir de str[i].
Definition: string_tool.cpp:209
trimQuote
void trimQuote(std::string &word)
Elimina comillas ['] ["] del principio o final de 'word'.
Definition: string_tool.cpp:121