Thread: Easy Way To Replace Strings...

  1. #1
    Registered User
    Join Date
    Feb 2003
    Posts
    265

    Easy Way To Replace Strings...

    As some of you know i have been working on a pseudo-scripting mini-language, sofar its going prety good, thanks for asking (user defined functions, calling of language functions and user defined functions, math, dynamic reloading of the script and functions in it, as well as a bunch of other stuff is working well). However im looking for a GOOD way to simply replace pieces of strings. No im not a n00b who couldnt do it, but my method would be bloated, slow, and wasteful and im trying to keep this little project as neat and beautiful and simple as possible. Now for the infamous code tags DUN DUUUNNN DUUUUUNNNNN!!!
    Code:
    ...
    std::string myvar = "asdf";
    std::string line_im_processing = "i like to use $myvar in conversations about $myvar with my friends.";
    <MAGIC CODE TO REPLACE ALL OCCOURANCES OF $VARNAME WITH ITS AUCTUAL VALUE>
    Thats what im looking for. Dont tell me i have to just loop around looking, i KNOW there is always a simple elegant way to do things. I just havent had the inspiration as to what it is =P. Thanks for all the help guys, i know im kinda thick headed sometimes when i get a weird way of how to do it in my head, but ur always there to offer me words of "wtf is that nutball up to THIS time?!" =P

  2. #2
    Registered User
    Join Date
    May 2003
    Posts
    1,619
    Do you want to use ONLY $myvar, or any arbitrary name starting with $?

    If the second, then I suggest using a std::map<std::string, std::string> to store key/value pairs. In this case, the key would be "myvar" (or "$myvar") and the value would be the string to replace with.

    You probably want to use some kind of string tokenizer to parse your scripts, I recommend downloading Boost and installing it; it's extentions to the standard library (by most of the same people who did the STL). They have a good string tokenizer template class for easy tokenizing. You can iterate through each token of a string, and build the desired output string.

    Here is one example:

    Code:
    #include <iostream>
    #include <string>
    #include <map>
    #include<boost/tokenizer.hpp>
    
    
    //typedefs to make life easier
    typedef std::map<std::string,std::string> stringmap;
    typedef boost::char_separator<char> cSeparator;
    typedef boost::tokenizer<cSeparator> sTokenizer;
    typedef sTokenizer::iterator stIter;
    
    int main()
    {
        // Create the variable map:
        stringmap smVariables;
        smVariables["$myVar"] = "<<Contents>>";
    
        //Create some strings:
        std::string input("This is $notavar   '$myVar':    $myVar");
        std::string output;
        std::string tokens;
    
        // Setup the separator list:
        cSeparator sep(" \t\n");
        // Create the tokenizer:
        sTokenizer tok(input,sep);
        //Loop through the tokens:
        for(stIter i=tok.begin(); i!=tok.end();++i){
            tokens += "[" + *i + "]";
            if((*i)[0] == '$') // Tokens beginning with '$' get replaced.
                output += "[" + smVariables[*i] + "]";
            else
                output += "[" + *i + "]";
        }
    
        // Let's see how it works.
        std::cout << "Input  : " << input << std::endl;
        std::cout << "Tokens : " << tokens << std::endl;
        std::cout << "Output : " << output << std::endl;
    }
    The output of that test case was:

    Code:
    Input  : This is $notavar   '$myVar':    $myVar
    Tokens : [This][is][$notavar]['$myVar':][$myVar]
    Output : [This][is][]['$myVar':][<<Contents>>]
    This string tokenizer is capable of more powerful things, so it should be able to handle whatever you need.

    If you don't want to use the tokenizer, you need to find a way to isolate a substring which contains the variable name, and replace it in a similar fashion.
    Last edited by Cat; 07-27-2003 at 04:22 PM.

  3. #3
    Registered User
    Join Date
    Feb 2003
    Posts
    265
    The problem is that tokenization will only work when its alone seperated by spaces (or another standard character). Im looking for a more comprehensive way to do it. If i have $bob = "ddd" and i type asdf$bobize it should drop / replace $bob with ddd leaving asdfdddize. The map idea is very good. I was thinking about that already. Isnt there a STL algorithm that would do this? replace_copy_if_find or something? Im grasping at straws from what i saw in my nice popup list of functions that my ide spawned for me. Im still very interested in everybodys ideas.

  4. #4
    Registered User
    Join Date
    May 2003
    Posts
    1,619
    In that case, you iterate through the map and use the string's find() method to identify substrings of the key, and then replace them with I believe, string::replace().

  5. #5
    Cat without Hat CornedBee's Avatar
    Join Date
    Apr 2003
    Posts
    8,895
    However, finding "$bob" out of "$bobize" is gonna be somewhat tricky. Can take very long, especially if the user types something insane like "replace$thisMySpaceIsBrokenMySpaceIsBrokenMySpace IsBrokenMySpaceIsBrokenMySpaceIsBrokenMySpaceIsBro kenMySpaceIsBrokenMySpaceIsBrokenMySpaceIsBrokenMy SpaceIsBrokenMySpaceIsBrokenMySpaceIsBrokenMySpace IsBrokenMySpaceIsBrokenMySpaceIsBrokenMySpaceIsBro kenMySpaceIsBrokenMySpaceIsBrokenMySpaceIsBrokenMy SpaceIsBrokenMySpaceIsBrokenMySpaceIsBrokenMySpace IsBrokenMySpaceIsBrokenMySpaceIsBrokenMySpaceIsBro kenMySpaceIsBrokenMySpaceIsBrokenMySpaceIsBrokenMy SpaceIsBrokenMySpaceIsBrokenMySpaceIsBrokenMySpace IsBrokenMySpaceIsBrokenMySpaceIsBrokenMySpaceIsBro kenMySpaceIsBrokenMySpaceIsBrokenMySpaceIsBrokenMy SpaceIsBrokenMySpaceIsBrokenMySpaceIsBrokenMySpace IsBrokenMySpaceIsBrokenMySpaceIsBrokenMySpaceIsBro kenMySpaceIsBrokenMySpaceIsBrokenMySpaceIsBroken".
    This means you have to check everything after the $ for being a variable, snipping off one character at a time, and you have to start with the longest possible name (else short variable names override long).
    All the buzzt!
    CornedBee

    "There is not now, nor has there ever been, nor will there ever be, any programming language in which it is the least bit difficult to write bad code."
    - Flon's Law

  6. #6
    Registered User
    Join Date
    May 2003
    Posts
    1,619
    I had considered that as well, aftre I posted last. Why not make variable names look like $this$ ? Then it's unambiguous which variable name you mean.

    Oh, and CornedBee, you wouldn't check character by character, you'd have a list of variables and you'd iterate them in reverse lexicographical order (so you would replace all instances of $abcde before $abc). But making them start and end with a special symbol is easier.

  7. #7
    Cat without Hat CornedBee's Avatar
    Join Date
    Apr 2003
    Posts
    8,895
    Perl uses this syntax for such cases:
    ${varname}asdadsadaf
    All the buzzt!
    CornedBee

    "There is not now, nor has there ever been, nor will there ever be, any programming language in which it is the least bit difficult to write bad code."
    - Flon's Law

  8. #8
    Registered User
    Join Date
    Feb 2003
    Posts
    265
    First of all, i appreciate the replys. I think a map transversed via iterator using basic_string::find functions would be probablly the best way for my particular problem. However your last post raises an interesting problem i didnt think about (although it would be prety obvious after i got intermittent errors) with the whole $as vs $asdf case. I would have to transverse the map of strings by length, using longest first, else i would get problems. The terminating $ is a good idea, and im still unsure exactly how i want to structure it. Lots of options, and im still debating the best way. Thanks alot for the ideas and help guys.

  9. #9
    Registered User
    Join Date
    May 2003
    Posts
    1,619
    Here's something simple I cooked up. Pretty basic, it simply searches for a pair of matching $ $s, takes what's between them and searches the map for it, and replaces.


    Code:
    #include <iostream>
    #include <string>
    #include <map>
    
    typedef std::map<std::string, std::string> stringMap;
    
    std::string parse(std::string s, const stringMap& m){
        std::string::size_type first = 0,second;
        while(true){
            if ((first = s.find("$",first)) == s.npos) break;
            if ((second = s.find("$",first + 1)) == s.npos) break;
            
            std::string key = s.substr(first + 1, second-first-1), val;
            stringMap::const_iterator i = m.find(key);
            if (i != m.end()) val = i->second;
            s.replace(first, second-first + 1, val);
    
            first = second + 1;
        }
        return s;
    }
    
    int main(){
        stringMap m;
        m["cd"] = "[Test string here]";
        std::string s = parse("ab$cd$$$efg$h$i$jkl",m);
        std::cout << s << std::endl;
        
    }
    This does the following replacements:

    $cd$ is replaced by [Test string here]
    $$ is replaced by nothing (key doesn't exist)
    $h$ is replaced by nothing (key doesn't exist)
    Last $ is left alone (it's unmatched)

    so the output is:

    Code:
    ab[Test string here]efgi$jkl
    This does present problems if you have any $s in the string that you don't want to be made into a variable name. You could use some kind of escape sequence for the character $, like use $$. You'd have to modify the position searching algorithm slightly; you'd probably want to code your own find() command.
    Last edited by Cat; 07-28-2003 at 12:35 PM.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Easy C# way to unescape HTML strings?
    By Cat in forum C# Programming
    Replies: 3
    Last Post: 11-15-2006, 11:59 PM
  2. strings in C++
    By elad in forum C++ Programming
    Replies: 11
    Last Post: 05-20-2006, 02:27 AM
  3. Problems with strings as key in STL maps
    By all_names_taken in forum C++ Programming
    Replies: 3
    Last Post: 01-17-2006, 11:34 AM
  4. Getting the number of strings in a STRINGTABLE resource
    By eth0 in forum Windows Programming
    Replies: 1
    Last Post: 09-30-2005, 02:57 AM
  5. Need a new way to replace a constant
    By RustGod in forum C++ Programming
    Replies: 5
    Last Post: 10-29-2001, 03:05 PM