replace.cc Source File

Main Page Namespace List Compound List File List Compound Members File Members

# replace.cc

Go to the documentation of this file.

    00001 /*
    00002  *
    00003  *  This file  is part of the PCRE++ Class Library.
    00004  *
    00005  *  By  accessing  this software,  PCRE++, you  are  duly informed
    00006  *  of and agree to be  bound  by the  conditions  described below
    00007  *  in this notice:
    00008  *
    00009  *  This software product,  PCRE++,  is developed by Thomas Linden
    00010  *  and copyrighted (C) 2002-2003 by Thomas Linden,with all rights
    00011  *  reserved.
    00012  *
    00013  *  There  is no charge for PCRE++ software.  You can redistribute
    00014  *  it and/or modify it under the terms of the GNU  Lesser General
    00015  *  Public License, which is incorporated by reference herein.
    00016  *
    00017  *  PCRE++ is distributed WITHOUT ANY WARRANTY, IMPLIED OR EXPRESS,
    00018  *  OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE or that
    00019  *  the use of it will not infringe on any third party's intellec-
    00020  *  tual property rights.
    00021  *
    00022  *  You should have received a copy of the GNU Lesser General Public
    00023  *  License along with PCRE++.  Copies can also be obtained from:
    00024  *
    00025  *    http://www.gnu.org/licenses/lgpl.txt
    00026  *
    00027  *  or by writing to:
    00028  *
    00029  *  Free Software Foundation, Inc.
    00030  *  59 Temple Place, Suite 330
    00031  *  Boston, MA 02111-1307
    00032  *  USA
    00033  *
    00034  *  Or contact:
    00035  *
    00036  *   "Thomas Linden" <tom@daemon.de>
    00037  *
    00038  *
    00039  */
    00040
    00041
    00042 #include "pcre++.h"
    00043
    00044 using namespace std;
    00045 using namespace pcrepp;
    00046
    00047 /*
    00048  * replace method
    00049  */
    00050
    00051 string Pcre::replace(const string& piece, const string& with) {
    00052   /*
    00053    * Pcre::replace version by "Marcus Kramer" <marcus.kramer@scherrer.de>
    00054    */
    00055   string Replaced(piece);
    00056
    00057   bool bReplaced = false;
    00058   int  iReplaced = -1;
    00059
    00060   __pcredebug << "replace: " << piece << " with: " << with << endl;
    00061
    00062   /*
    00063    * certainly we need an anchor, we want to check if the whole arg is in brackets
    00064    * //Pcre braces("^[^\\\\]\\(.*[^\\\\]\\)$"); // perlish: [^\\]\(.*[^\\]\)
    00065    *
    00066    * There's no reason, not to add brackets in general.
    00067    * It's more comfortable, cause we wants to start with $1 at all,
    00068    * also if we set the whole arg in brackets!
    00069    */
    00070
    00071   /* recreate the p_pcre* objects to avoid memory leaks */
    00072   pcre_free(p_pcre);
    00073   pcre_free(p_pcre_extra);
    00074
    00075   pcre       *_p = NULL;
    00076   pcre_extra *_e = NULL;;
    00077
    00078   p_pcre = _p;
    00079   p_pcre_extra = _e;
    00080
    00081   if (! _have_paren ) {
    00082     string::size_type p_open, p_close;
    00083     p_open  = _expression.find_first_of("(");
    00084     p_close = _expression.find_first_of(")");
    00085     if ( p_open == string::npos && p_close == string::npos ) {
    00086       /*
    00087        * Well, _expression completely lacks of parens, which are
    00088        * required for search/replace operation. So add parens automatically.
    00089        * Note, that we add 2 pairs of parens so that we finally have $0 matchin
    00090        * the whole expression and $1 matching the inner side (which is in this
    00091        * case the very same string.
    00092        * We do this for perl compatibility. If the expression already contains
    00093        * parens, the whole match will produce $0 for us, so in this case we
    00094        * have no problem
    00095        */
    00096       _expression = "((" + _expression + "))";
    00097     }
    00098     else {
    00099       /*
    00100        * Add parens to the very beginning and end of the expression
    00101        * so that we have $0. I don't care if the user already supplied
    00102        * double-parentesed experssion (e.g. "((1))"), because PCRE seems
    00103        * to eat redundant parenteses, e.g. "((((1))))" returns the same
    00104        * result as "((1))".
    00105        */
    00106       _expression = "(" + _expression;
    00107       _expression=_expression + ")";
    00108     }
    00109
    00110     _have_paren = true;
    00111   }
    00112
    00113   __pcredebug << "_expression: " << _expression << endl;
    00114
    00115   Compile(_flags);
    00116
    00117   if(search(piece)) {
    00118     /* we found at least one match */
    00119
    00120     // sure we must resolve $1 for ever piece we found especially for "g"
    00121     // so let's just create that var, we resolve it when we needed!
    00122     string use_with;
    00123
    00124
    00125     if(!global_t) {
    00126       // here we can resolve vars if option g is not set
    00127       use_with = _replace_vars(with);
    00128
    00129       if(matched() && matches() >= 1) {
    00130         __pcredebug << "matches: " << matches() << endl;
    00131         int len = get_match_end() - get_match_start() + 1;
    00132         Replaced.replace(get_match_start(0), len, use_with);
    00133         bReplaced  = true;
    00134         iReplaced = 0;
    00135       }
    00136     }
    00137     else {
    00138       /* global replace */
    00139
    00140       // in global replace we just need to remember our position
    00141       // so let's initialize it first
    00142       int match_pos = 0;
    00143       while( search( Replaced, match_pos ) ) {
    00144         int len = 0;
    00145
    00146         // here we need to resolve the vars certainly for every hit.
    00147         // could be different content sometimes!
    00148         use_with = _replace_vars(with);
    00149
    00150         len = get_match_end() - get_match_start() + 1;
    00151         Replaced.replace(get_match_start(0), len, use_with);
    00152
    00153         //# Next run should begin after the last char of the stuff we put in the text
    00154         match_pos = ( use_with.length() - len ) + get_match_end() + 1;
    00155
    00156         bReplaced  = true;
    00157         ++iReplaced;
    00158       }
    00159     }
    00160   }
    00161
    00162   did_match   = bReplaced;
    00163   num_matches = iReplaced;
    00164
    00165   return Replaced;
    00166 }
    00167
    00168
    00169
    00170
    00171
    00172 string Pcre::_replace_vars(const string& piece) {
    00173   /*
    00174    * Pcre::_replace_vars version by "Marcus Kramer" <marcus.kramer@scherrer.de>
    00175    */
    00176   string with  = piece;
    00177   Pcre dollar("\\$([0-9]+)");
    00178
    00179   while ( dollar.search( with ) ) {
    00180     // let's do some conversion first
    00181     __pcredebug << "Pcre::dollar matched: " << piece << ". Match(0): " << dollar.get_match(0) << endl;
    00182     int iBracketIndex = atoi( dollar.get_match(0).data() );
    00183     string sBracketContent = get_match(iBracketIndex);
    00184
    00185     // now we can splitt the stuff
    00186     string sSubSplit = "\\$" + dollar.get_match(0);
    00187     Pcre subsplit(sSubSplit);
    00188
    00189     // normally 2 (or more) parts, the one in front of and the other one after "$1"
    00190     vector<string> splitted = subsplit.split(with);
    00191     string Replaced;
    00192
    00193     for(size_t pos=0; pos < splitted.size(); pos++) {
    00194       if( pos == ( splitted.size() - 1 ) )
    00195         Replaced += splitted[pos];
    00196       else
    00197         Replaced += splitted[pos] + sBracketContent;
    00198     }
    00199     with = Replaced; // well, one part is done
    00200   }
    00201   return with;
    00202 }