CUBRID Engine  latest
string_regex.cpp
Go to the documentation of this file.
1 /*
2  * Copyright 2008 Search Solution Corporation
3  * Copyright 2016 CUBRID Corporation
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  *
17  */
18 
19 //
20 // string_regex - definitions and functions related to regular expression
21 //
22 
23 #include "string_regex.hpp"
24 
25 #include "locale_helper.hpp"
26 #include "error_manager.h"
27 #include "memory_alloc.h"
28 #include "language_support.h"
29 
30 #include <algorithm>
31 #include <regex>
32 #include <string>
33 
34 namespace cubregex
35 {
36 
37  compiled_regex::compiled_regex () : regex (NULL), pattern (NULL)
38  {}
39 
40  compiled_regex::~compiled_regex ()
41  {
42  clear (regex, pattern);
43  }
44 
45  std::string
46  parse_regex_exception (std::regex_error &e)
47  {
48  std::string error_message;
49  using namespace std::regex_constants;
50  switch (e.code ())
51  {
52  case error_collate:
53  error_message.assign ("regex_error(error_collate): the expression contains an invalid collating element name");
54  break;
55  case error_ctype:
56  error_message.assign ("regex_error(error_ctype): the expression contains an invalid character class name");
57  break;
58  case error_escape:
59  error_message.assign ("regex_error(error_escape): the expression contains an invalid escaped character or a trailing escape");
60  break;
61  case error_backref:
62  error_message.assign ("regex_error(error_backref): the expression contains an invalid back reference");
63  break;
64  case error_brack:
65  error_message.assign ("regex_error(error_brack): the expression contains mismatched square brackets ('[' and ']')");
66  break;
67  case error_paren:
68  error_message.assign ("regex_error(error_paren): the expression contains mismatched parentheses ('(' and ')')");
69  break;
70  case error_brace:
71  error_message.assign ("regex_error(error_brace): the expression contains mismatched curly braces ('{' and '}')");
72  break;
73  case error_badbrace:
74  error_message.assign ("regex_error(error_badbrace): the expression contains an invalid range in a {} expression");
75  break;
76  case error_range:
77  error_message.assign ("regex_error(error_range): the expression contains an invalid character range (e.g. [b-a])");
78  break;
79  case error_space:
80  error_message.assign ("regex_error(error_space): there was not enough memory to convert the expression into a finite state machine");
81  break;
82  case error_badrepeat:
83  error_message.assign ("regex_error(error_badrepeat): one of *?+{ was not preceded by a valid regular expression");
84  break;
85  case error_complexity:
86  error_message.assign ("regex_error(error_complexity): the complexity of an attempted match exceeded a predefined level");
87  break;
88  case error_stack:
89  error_message.assign ("regex_error(error_stack): there was not enough memory to perform a match");
90  break;
91  default:
92  error_message.assign ("regex_error(error_unknown)");
93  break;
94  }
95  return error_message;
96  }
97 
98  int
99  parse_match_type (std::regex_constants::syntax_option_type &reg_flags, std::string &opt_str)
100  {
101  int error_status = NO_ERROR;
102 
103  auto mt_iter = opt_str.begin ();
104  while ((mt_iter != opt_str.end ()) && (error_status == NO_ERROR))
105  {
106  char opt = *mt_iter;
107  switch (opt)
108  {
109  case 'c':
110  reg_flags &= ~std::regex_constants::icase;
111  break;
112  case 'i':
113  reg_flags |= std::regex_constants::icase;
114  break;
115  default:
116  error_status = ER_QPROC_INVALID_PARAMETER;
117  break;
118  }
119  ++mt_iter;
120  }
121 
122  return error_status;
123  }
124 
125  void
126  clear (cub_regex_object *&regex, char *&pattern)
127  {
128  if (regex != NULL)
129  {
130  delete regex;
131  regex = NULL;
132  }
133 
134  if (pattern != NULL)
135  {
136  db_private_free_and_init (NULL, pattern);
137  }
138  }
139 
140  bool check_should_recompile (const cub_regex_object *compiled_regex, const char *compiled_pattern,
141  const std::string &pattern,
142  const std::regex_constants::syntax_option_type reg_flags)
143  {
144  /* regex must be recompiled if regex object is not specified or different flags are set */
145  if (compiled_regex == NULL || reg_flags != compiled_regex->flags ())
146  {
147  return true;
148  }
149 
150  /* regex must be recompiled if pattern is not specified or compiled pattern does not match current pattern */
151  if (compiled_pattern == NULL || pattern.size () != strlen (compiled_pattern)
152  || pattern.compare (compiled_pattern) != 0)
153  {
154  return true;
155  }
156 
157  return false;
158  }
159 
160  int compile (cub_regex_object *&compiled_regex, const char *pattern,
161  const std::regex_constants::syntax_option_type reg_flags, const LANG_COLLATION *collation)
162  {
163  int error_status = NO_ERROR;
164 
165  std::wstring pattern_wstring;
166  if (cublocale::convert_to_wstring (pattern_wstring, std::string (pattern), collation->codeset) == false)
167  {
168  error_status = ER_QSTR_BAD_SRC_CODESET;
169  return error_status;
170  }
171 
172  try
173  {
174 #if defined(WINDOWS)
175  /* HACK: collating element features doesn't work well on Windows.
176  * And lookup_collatename is not invoked when regex pattern has collating element.
177  * It is hacky code finding collating element pattern and throw error.
178  */
179  wchar_t *collate_elem_pattern = L"[[.";
180  int found = pattern_wstring.find ( std::wstring (collate_elem_pattern));
181  if (found != std::wstring::npos)
182  {
183  throw std::regex_error (std::regex_constants::error_collate);
184  }
185 #endif
186 
187  // delete to avoid memory leak
188  if (compiled_regex != NULL)
189  {
190  delete compiled_regex;
191  }
192 
193  compiled_regex = new cub_regex_object ();
194  if (compiled_regex == NULL)
195  {
196  error_status = ER_OUT_OF_VIRTUAL_MEMORY;
197  }
198  else
199  {
200  std::locale loc = cublocale::get_locale (std::string ("utf-8"), cublocale::get_lang_name (collation));
201  compiled_regex->imbue (loc);
202  compiled_regex->assign (pattern_wstring, reg_flags);
203  }
204  }
205  catch (std::regex_error &e)
206  {
207  // regex compilation exception
208  error_status = ER_REGEX_COMPILE_ERROR;
209  std::string error_message = parse_regex_exception (e);
210  er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, error_status, 1, error_message.c_str ());
211  }
212 
213  return error_status;
214  }
215 
216  int search (int &result, const cub_regex_object &reg, const std::string &src, const INTL_CODESET codeset)
217  {
218  int error_status = NO_ERROR;
219  bool is_matched = false;
220 
221  std::wstring src_wstring;
222  if (cublocale::convert_to_wstring (src_wstring, src, codeset) == false)
223  {
224  error_status = ER_QSTR_BAD_SRC_CODESET;
225  result = V_FALSE;
226  return error_status;
227  }
228 
229  try
230  {
231 #if defined(WINDOWS)
232  /* HACK: case insensitive doesn't work well on Windows.
233  * This code transforms source string into lowercase
234  * and perform searching regular expression pattern.
235  */
236  if (reg.flags() & std::regex_constants::icase)
237  {
238  std::wstring src_lower;
239  src_lower.resize (src_wstring.size ());
240  std::transform (src_wstring.begin(), src_wstring.end(), src_lower.begin(), ::towlower);
241  is_matched = std::regex_search (src_lower, reg);
242  }
243  else
244  {
245  is_matched = std::regex_search (src_wstring, reg);
246  }
247 #else
248  is_matched = std::regex_search (src_wstring, reg);
249 #endif
250  }
251  catch (std::regex_error &e)
252  {
253  // regex execution exception
254  is_matched = false;
255  error_status = ER_REGEX_EXEC_ERROR;
256  std::string error_message = parse_regex_exception (e);
257  er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, error_status, 1, error_message.c_str ());
258  }
259 
260  result = is_matched ? V_TRUE : V_FALSE;
261  return error_status;
262  }
263 
264  int count (int &result, const cub_regex_object &reg, const std::string &src, const int position,
265  const INTL_CODESET codeset)
266  {
267  assert (position >= 0);
268 
269  int error_status = NO_ERROR;
270 
271  std::wstring src_wstring;
272  if (cublocale::convert_to_wstring (src_wstring, src, codeset) == false)
273  {
274  error_status = ER_QSTR_BAD_SRC_CODESET;
275  return error_status;
276  }
277 
278  /* split source string by position value */
279  std::wstring target (
280  src_wstring.substr (position, src_wstring.size () - position)
281  );
282 
283 #if defined(WINDOWS)
284  /* HACK: case insensitive doesn't work well on Windows.
285  * This code transforms source string into lowercase
286  * and perform searching regular expression pattern.
287  */
288  std::wstring target_lower;
289  if (reg.flags() & std::regex_constants::icase)
290  {
291  target_lower.resize (target.size ());
292  std::transform (target.begin(), target.end(), target_lower.begin(), ::towlower);
293  }
294  else
295  {
296  target_lower = target;
297  }
298 #endif
299 
300  int count = 0;
301  try
302  {
303 #if defined(WINDOWS)
304  auto reg_iter = cub_regex_iterator (target_lower.begin (), target_lower.end (), reg);
305 #else
306  auto reg_iter = cub_regex_iterator (target.begin (), target.end (), reg);
307 #endif
308  auto reg_end = cub_regex_iterator ();
309  count = std::distance (reg_iter, reg_end);
310  }
311  catch (std::regex_error &e)
312  {
313  // regex execution exception, error_complexity or error_stack
314  error_status = ER_REGEX_EXEC_ERROR;
315  std::string error_message = cubregex::parse_regex_exception (e);
316  er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, error_status, 1, error_message.c_str ());
317  }
318 
319  /* assgin result */
320  result = count;
321  return error_status;
322  }
323 
324  int instr (int &result, const cub_regex_object &reg, const std::string &src,
325  const int position, const int occurrence, const int return_opt, const INTL_CODESET codeset)
326  {
327  assert (position >= 0);
328  assert (occurrence >= 1);
329 
330  int error_status = NO_ERROR;
331 
332  std::wstring src_wstring;
333  if (cublocale::convert_to_wstring (src_wstring, src, codeset) == false)
334  {
335  error_status = ER_QSTR_BAD_SRC_CODESET;
336  return error_status;
337  }
338 
339  /* split source string by position value */
340  std::wstring target (
341  src_wstring.substr (position, src_wstring.size () - position)
342  );
343 
344 #if defined(WINDOWS)
345  /* HACK: case insensitive doesn't work well on Windows.
346  * This code transforms source string into lowercase
347  * and perform searching regular expression pattern.
348  */
349  std::wstring target_lower;
350  if (reg.flags() & std::regex_constants::icase)
351  {
352  target_lower.resize (target.size ());
353  std::transform (target.begin(), target.end(), target_lower.begin(), ::towlower);
354  }
355  else
356  {
357  target_lower = target;
358  }
359 #endif
360 
361  int match_idx = -1;
362  try
363  {
364 #if defined(WINDOWS)
365  auto reg_iter = cub_regex_iterator (target_lower.begin (), target_lower.end (), reg);
366 #else
367  auto reg_iter = cub_regex_iterator (target.begin (), target.end (), reg);
368 #endif
369  auto reg_end = cub_regex_iterator ();
370 
371  int n = 1;
372  while (reg_iter != reg_end)
373  {
374  /* match */
375  if (n == occurrence)
376  {
377  cub_regex_results match_result = *reg_iter;
378  match_idx = match_result.position ();
379  if (return_opt == 1)
380  {
381  match_idx += reg_iter->length ();
382  }
383  break;
384  }
385  ++reg_iter;
386  ++n;
387  }
388 
389  if (match_idx != -1)
390  {
391  result = position + match_idx + 1;
392  }
393  else
394  {
395  result = 0;
396  }
397  }
398  catch (std::regex_error &e)
399  {
400  // regex execution exception, error_complexity or error_stack
401  error_status = ER_REGEX_EXEC_ERROR;
402  result = 0;
403  std::string error_message = cubregex::parse_regex_exception (e);
404  er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, error_status, 1, error_message.c_str ());
405  }
406 
407  return error_status;
408  }
409 
410 #if defined(WINDOWS)
411  /* HACK: case insensitive doesn't work well on Windows.
412  * This code transforms source string into lowercase
413  * and perform searching regular expression pattern.
414  */
415  int replace (std::string &result, const cub_regex_object &reg, const std::string &src,
416  const std::string &repl, const int position,
417  const int occurrence, const INTL_CODESET codeset)
418  {
419  assert (position >= 0);
420  assert (occurrence >= 0);
421 
422  int error_status = NO_ERROR;
423 
424  std::wstring src_wstring;
425  if (cublocale::convert_to_wstring (src_wstring, src, codeset) == false)
426  {
427  error_status = ER_QSTR_BAD_SRC_CODESET;
428  return error_status;
429  }
430 
431  std::wstring repl_wstring;
432  if (cublocale::convert_to_wstring (repl_wstring, repl, codeset) == false)
433  {
434  error_status = ER_QSTR_BAD_SRC_CODESET;
435  return error_status;
436  }
437 
438  /* split source string by position value */
439  std::wstring result_wstring (src_wstring.substr (0, position));
440  std::wstring target (
441  src_wstring.substr (position, src_wstring.size () - position)
442  );
443 
444  std::wstring target_lowercase;
445  if (reg.flags() & std::regex_constants::icase)
446  {
447  target_lowercase.resize (target.size ());
448  std::transform (target.begin(), target.end(), target_lowercase.begin(), ::towlower);
449  }
450  else
451  {
452  target_lowercase = target;
453  }
454 
455  try
456  {
457  auto reg_iter = cub_regex_iterator (target_lowercase.begin (), target_lowercase.end (), reg);
458  auto reg_end = cub_regex_iterator ();
459 
460  int last_pos = 0;
461  int match_pos = -1;
462  size_t match_length;
463  int n = 1;
464  auto out = std::back_inserter (result_wstring);
465 
466  cub_regex_results match_result;
467  while (reg_iter != reg_end)
468  {
469  match_result = *reg_iter;
470 
471  /* prefix */
472  match_pos = match_result.position ();
473  match_length = match_result.length ();
474  std::wstring match_prefix = target.substr (last_pos, match_pos - last_pos);
475  out = std::copy (match_prefix.begin (), match_prefix.end (), out);
476 
477  /* match */
478  if (n == occurrence || occurrence == 0)
479  {
480  out = match_result.format (out, repl_wstring);
481  }
482  else
483  {
484  std::wstring match_str = target.substr (match_pos, match_length);
485  out = std::copy (match_str.begin (), match_str.end (), out);
486  }
487 
488  ++reg_iter;
489 
490  /* suffix */
491  last_pos = match_pos + match_length;
492  if (((occurrence != 0) && (n == occurrence)) || reg_iter == reg_end)
493  {
494  std::wstring match_suffix = target.substr (match_pos + match_length, std::string::npos);
495  out = std::copy (match_suffix.begin (), match_suffix.end (), out);
496  if (occurrence != 0 && n == occurrence)
497  {
498  break;
499  }
500  }
501  ++n;
502  }
503 
504  /* nothing matched */
505  if (match_pos == -1 && reg_iter == reg_end)
506  {
507  out = std::copy (target.begin (), target.end (), out);
508  }
509 
510  if (cublocale::convert_to_string (result, result_wstring, codeset) == false)
511  {
512  error_status = ER_QSTR_BAD_SRC_CODESET;
513  return error_status;
514  }
515  }
516  catch (std::regex_error &e)
517  {
518  // regex execution exception, error_complexity or error_stack
519  error_status = ER_REGEX_EXEC_ERROR;
520  result.clear ();
521  std::string error_message = cubregex::parse_regex_exception (e);
522  er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, error_status, 1, error_message.c_str ());
523  }
524 
525  return error_status;
526  }
527 #else
528  int replace (std::string &result, const cub_regex_object &reg, const std::string &src,
529  const std::string &repl, const int position,
530  const int occurrence, const INTL_CODESET codeset)
531  {
532  assert (position >= 0);
533  assert (occurrence >= 0);
534 
535  int error_status = NO_ERROR;
536 
537  std::wstring src_wstring;
538  if (cublocale::convert_to_wstring (src_wstring, src, codeset) == false)
539  {
540  error_status = ER_QSTR_BAD_SRC_CODESET;
541  return error_status;
542  }
543 
544  std::wstring repl_wstring;
545  if (cublocale::convert_to_wstring (repl_wstring, repl, codeset) == false)
546  {
547  error_status = ER_QSTR_BAD_SRC_CODESET;
548  return error_status;
549  }
550 
551  /* split source string by position value */
552  std::wstring result_wstring (src_wstring.substr (0, position));
553  std::wstring target (
554  src_wstring.substr (position, src_wstring.size () - position)
555  );
556 
557  int match_pos = -1;
558  size_t match_length = 0;
559  try
560  {
561  if (occurrence == 0)
562  {
563  result_wstring.append (
564  std::regex_replace (target, reg, repl_wstring)
565  );
566  }
567  else
568  {
569  auto reg_iter = cub_regex_iterator (target.begin (), target.end (), reg);
570  auto reg_end = cub_regex_iterator ();
571 
572  int n = 1;
573  auto out = std::back_inserter (result_wstring);
574 
575  while (reg_iter != reg_end)
576  {
577  const cub_regex_results match_result = *reg_iter;
578 
579  std::wstring match_prefix = match_result.prefix ().str ();
580  out = std::copy (match_prefix.begin (), match_prefix.end (), out);
581 
582  /* match */
583  match_pos = match_result.position ();
584  match_length = match_result.length ();
585  if (n == occurrence)
586  {
587  out = match_result.format (out, repl_wstring);
588  }
589  else
590  {
591  std::wstring match_str = match_result.str ();
592  out = std::copy (match_str.begin (), match_str.end (), out);
593  }
594 
595  ++reg_iter;
596 
597  /* suffix */
598  if (n == occurrence || reg_iter == reg_end)
599  {
600  /* occurrence option specified or end of matching */
601  std::wstring match_suffix = match_result.suffix (). str ();
602  out = std::copy (match_suffix.begin (), match_suffix.end (), out);
603  break;
604  }
605  ++n;
606  }
607 
608  /* nothing matched */
609  if (match_pos == -1 && reg_iter == reg_end)
610  {
611  out = std::copy (target.begin (), target.end (), out);
612  }
613  }
614 
615  if (cublocale::convert_to_string (result, result_wstring, codeset) == false)
616  {
617  error_status = ER_QSTR_BAD_SRC_CODESET;
618  return error_status;
619  }
620 
621  }
622  catch (std::regex_error &e)
623  {
624  // regex execution exception, error_complexity or error_stack
625  error_status = ER_REGEX_EXEC_ERROR;
626  result.clear ();
627  std::string error_message = cubregex::parse_regex_exception (e);
628  er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, error_status, 1, error_message.c_str ());
629  }
630 
631  return error_status;
632  }
633 #endif
634 
635  int substr (std::string &result, bool &is_matched, const cub_regex_object &reg, const std::string &src,
636  const int position, const int occurrence, const INTL_CODESET codeset)
637  {
638  assert (position >= 0);
639  assert (occurrence >= 1);
640 
641  int error_status = NO_ERROR;
642  is_matched = false;
643 
644  std::wstring src_wstring;
645  if (cublocale::convert_to_wstring (src_wstring, src, codeset) == false)
646  {
647  error_status = ER_QSTR_BAD_SRC_CODESET;
648  return error_status;
649  }
650 
651  /* split source string by position value */
652  std::wstring result_wstring;
653  std::wstring target (
654  src_wstring.substr (position, src_wstring.size () - position)
655  );
656 
657 #if defined(WINDOWS)
658  /* HACK: case insensitive doesn't work well on Windows.
659  * This code transforms source string into lowercase
660  * and perform searching regular expression pattern.
661  */
662  std::wstring target_lower;
663  if (reg.flags() & std::regex_constants::icase)
664  {
665  target_lower.resize (target.size ());
666  std::transform (target.begin(), target.end(), target_lower.begin(), ::towlower);
667  }
668  else
669  {
670  target_lower = target;
671  }
672 #endif
673 
674  int match_pos = -1;
675  size_t match_length = 0;
676  try
677  {
678 #if defined(WINDOWS)
679  auto reg_iter = cub_regex_iterator (target_lower.begin (), target_lower.end (), reg);
680 #else
681  auto reg_iter = cub_regex_iterator (target.begin (), target.end (), reg);
682 #endif
683  auto reg_end = cub_regex_iterator ();
684  auto out = std::back_inserter (result_wstring);
685 
686  int n = 1;
687  while (reg_iter != reg_end)
688  {
689  cub_regex_results match_result = *reg_iter;
690 
691  /* match */
692  match_pos = match_result.position ();
693  match_length = match_result.length ();
694  if (n == occurrence)
695  {
696  std::wstring match_str = target.substr (match_pos, match_length);
697  out = std::copy (match_str.begin (), match_str.end (), out);
698  is_matched = true;
699  break;
700  }
701  ++reg_iter;
702  ++n;
703  }
704 
705  if (cublocale::convert_to_string (result, result_wstring, codeset) == false)
706  {
707  error_status = ER_QSTR_BAD_SRC_CODESET;
708  return error_status;
709  }
710 
711  }
712  catch (std::regex_error &e)
713  {
714  // regex execution exception, error_complexity or error_stack
715  error_status = ER_REGEX_EXEC_ERROR;
716  result.clear ();
717  std::string error_message = cubregex::parse_regex_exception (e);
718  er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, error_status, 1, error_message.c_str ());
719  }
720 
721  return error_status;
722  }
723 }
#define ER_REGEX_COMPILE_ERROR
Definition: error_code.h:1362
#define NO_ERROR
Definition: error_code.h:46
std::string get_lang_name(const LANG_COLLATION *lang_coll)
#define ER_QSTR_BAD_SRC_CODESET
Definition: error_code.h:744
int instr(int &result, const cub_regex_object &reg, const std::string &src, const int position, const int occurrence, const int return_opt, const INTL_CODESET codeset)
int compile(cub_regex_object *&compiled_regex, const char *pattern, const std::regex_constants::syntax_option_type reg_flags, const LANG_COLLATION *collation)
void er_set(int severity, const char *file_name, const int line_no, int err_id, int num_args,...)
INTL_CODESET codeset
#define ER_QPROC_INVALID_PARAMETER
Definition: error_code.h:963
#define assert(x)
std::locale get_locale(const std::string &charset, const std::string &lang)
#define ER_OUT_OF_VIRTUAL_MEMORY
Definition: error_code.h:50
int substr(std::string &result, bool &is_matched, const cub_regex_object &reg, const std::string &src, const int position, const int occurrence, const INTL_CODESET codeset)
#define NULL
Definition: freelistheap.h:34
#define db_private_free_and_init(thrd, ptr)
Definition: memory_alloc.h:141
int count(int &result, const cub_regex_object &reg, const std::string &src, const int position, const INTL_CODESET codeset)
int parse_match_type(std::regex_constants::syntax_option_type &reg_flags, std::string &opt_str)
bool convert_to_string(std::string &out, const std::wstring &in, const INTL_CODESET codeset)
#define ARG_FILE_LINE
Definition: error_manager.h:44
#define strlen(s1)
Definition: intl_support.c:43
#define ER_REGEX_EXEC_ERROR
Definition: error_code.h:1363
int replace(std::string &result, const cub_regex_object &reg, const std::string &src, const std::string &repl, const int position, const int occurrence, const INTL_CODESET codeset)
enum intl_codeset INTL_CODESET
Definition: intl_support.h:190
std::string parse_regex_exception(std::regex_error &e)
bool check_should_recompile(const cub_regex_object *compiled_regex, const char *compiled_pattern, const std::string &pattern, const std::regex_constants::syntax_option_type reg_flags)
bool convert_to_wstring(std::wstring &out, const std::string &in, const INTL_CODESET codeset)
int search(int &result, const cub_regex_object &reg, const std::string &src, const INTL_CODESET codeset)
void clear(cub_regex_object *&regex, char *&pattern)