Search & Replace function for LoadRunner

Sometimes it is necessary to process parameters in LoadRunner after they have been “captured” using web_reg_save() or similar methods. There is no built-in function to do this, and I’ve seen multiple horrific attempts at different kinds of Search & Replace methods over the years.

In light of this I decided to post the source for my working solution that does not eat memory, is fast and is LoadRunner parameter friendly. It can be used by anyone who has worked with LoadRunner before!
Examples:


// Store a string into "MyPar" parameter
lr_save_string("This is a string", "MyPar");

// For examples sake, convert it to URL encoded format
web_convert_param( "MyPar",
                   "SourceEncoding=PLAIN",
                   "TargetEncoding=URL", LAST); 

// Output the current result
lr_output_message("%s", lr_eval_string("{MyPar}"));

// Replace the ? characters with %20
lr_replace("MyPar", "+", "%20" );

// Output new result
lr_output_message("%s", lr_eval_string("{MyPar}"));

The following source can be copied into the VUSER_INIT action, at the end or stored as a separate file to be included in the script (your choice!)

// ----------------------------------------------------------------------------
//
// Description:
//    Search for and replace text within a string.
//
// Parameters:
//    src (in) - pointer to source string
//    from (in) - pointer to search text
//    to (in) - pointer to replacement text
//
// Returns:
//    Returns a pointer to dynamically-allocated memory containing string
//    with occurences of the text pointed to by 'from' replaced by with
//    the text pointed to by 'to'.
//
// Notes:
//    Do not use this directly in scripts unless you are a more advanced
//    user who knows C and string handling. See below for the function you
//    should use!
//
// ----------------------------------------------------------------------------
char *strReplace(const char *src, const char *from, const char *to)
{
  char *value;
  char *dst;
  char *match;
  int size;
  int fromlen;
  int tolen;

  // Find out the lengths of the source string, text to replace, and
  // the replacement text.
  size = strlen(src) + 1;
  fromlen = strlen(from);
  tolen = strlen(to);

  // Allocate the first chunk with enough for the original string.
  value = (char *)malloc(size);

  // We need to return 'value', so let's make a copy to mess around with.
  dst = value;

  // Before we begin, let's see if malloc was successful.
  if ( value != NULL )
  {
    // Loop until no matches are found.
    for ( ;; )
    {
      // Try to find the search text.
      match = (char *) strstr(src, from);
      if ( match != NULL )
      {
        // Found search text at location 'match'.
        // Find out how many characters to copy up to the 'match'.
        size_t count = match - src;

        // We are going to realloc, and for that we will need a
        // temporary pointer for safe usage.
        char *temp;

        // Calculate the total size the string will be after the
        // replacement is performed.
        size += tolen - fromlen;

        // Attempt to realloc memory for the new size.
        //
        // temp = realloc(value, size);
        temp = (char *)realloc(value, size);

        if ( temp == NULL )
        {
          // Attempt to realloc failed. Free the previously malloc'd
          // memory and return with our tail between our legs.
          free(value);
          return NULL;
        }

        // The call to realloc was successful. But we'll want to
        // return 'value' eventually, so let's point it to the memory
        // that we are now working with. And let's not forget to point
        // to the right location in the destination as well.
        dst = temp + (dst - value);
        value = temp;

        // Copy from the source to the point where we matched. Then
        // move the source pointer ahead by the amount we copied. And
        // move the destination pointer ahead by the same amount.
        memmove(dst, src, count);
        src += count;
        dst += count;

        // Now copy in the replacement text 'to' at the position of
        // the match. Adjust the source pointer by the text we replaced.
        // Adjust the destination pointer by the amount of replacement
        // text.
        memmove(dst, to, tolen);
        src += fromlen;
        dst += tolen;
      }
      else // No match found.
      {
        // Copy any remaining part of the string. This includes the null
        // termination character.
        strcpy(dst, src);
        break;
      }
    } // For Loop()
  }
  return value;
}

// ----------------------------------------------------------------------------
//
// Description:
//    Find and replace text within a LoadRunner string.
//
// Parameters:
//    lrparam (in)    - pointer to LoadRunner Parameter Name
//    findstr (in)    - pointer to text top search for
//    replacestr (in) - pointer to text to use as replacement
//
// Returns:
//    Returns an integer. 0=Error, 1=Success.
//
// Example:
//    lr_save_string( "This is a small test of the search and replace function", "LRParam");
//    lr_replace( "LRParam", "a", "-x-" );
//    lr_output_message( "%s", lr_eval_string("{LRParam}") );
//
// ----------------------------------------------------------------------------
int lr_replace( const char *lrparam, char *findstr, char *replacestr )
{
  int res = 0;
  char *result_str;
  char lrp[1024];

  // Finalize the LR Param Name
  sprintf( lrp, "{%s}", lrparam);

  // Do the Search and Replace
  result_str = strReplace( lr_eval_string(lrp), findstr, replacestr );

  // Process results
  if (result_str != NULL )
  {
    lr_save_string( result_str, lrparam );
    free( result_str );
    res = 1;
  }
  return res;
} // EOF
Advertisements

43 thoughts on “Search & Replace function for LoadRunner

  1. Hi……

    replace(const char *string, char *pattern, char *replace, char *match)
    {

    int length;
    int status;
    int eflag;
    char buf[1024] = “”;
    char out[1024] = “”;

    regex_t re;
    regmatch_t pmatch[128];
    lr_load_dll(“pcre3.dll”);

    if((status = regcomp(&re, pattern, REG_EXTENDED)) != 0){
    regerror(status, &re, buf, 120);
    lr_output_message(“Match PCRE Exit 2”);
    return 2;
    }

    while(status = regexec( &re, string, 1, pmatch, eflag)== 0){
    strncat(out, string, pmatch[0].rm_so);
    strcat(out, replace);
    string += pmatch[0].rm_eo;
    eflag = REG_NOTBOL;
    }
    strcat(out, string);
    lr_save_string(out, match);
    }

    You can get commands regrading software testing in MACROTESTING

  2. Dear Fiends,
    I have to copy GQV352233 value and past it into some other search text box it should do automatically.

    name=\”h_srmid\”></d

    Help me out of this
    Thanks
    HK

  3. Hi everyone. I was wondering whether someone has a way to convert xml script in to Base64 encode and after that it again decode for result.

    Thanks in advanced.

    Matt

  4. Hi,

    I am trying to use your code for string search and replace, but i am getting several compilation errors

    Action.c (43): illegal statement termination
    Action.c (43): skipping `char’
    Action.c (43): illegal expression
    Action.c (43): syntax error; found `char’ expecting `)’
    Action.c (43): type error: pointer expected
    Action.c (43): syntax error; found `char’ expecting `;’
    Action.c (43): illegal statement termination
    Action.c (43): skipping `char’
    Action.c (43): undeclared identifier `src’
    Action.c (43): type error: pointer expected
    Action.c (43): illegal expression
    Action.c (43): syntax error; found `char’ expecting `;’
    Action.c (43): illegal statement termination
    Action.c (43): skipping `char’
    Action.c (43): undeclared identifier `from’
    Action.c (43): type error: pointer expected
    Action.c (43): illegal expression
    Action.c (43): syntax error; found `char’ expecting `;’
    Action.c (43): illegal statement termination
    Action.c (43): skipping `char’
    Action.c (43): too many errors

    I am new to LoadRunner, would you please provide pre-requisite steps before copying this code to existing Loadrunner script, do i need to add any ‘include’ libraries to support this code, or need to declare any global variables.

    Please Advise!
    Sharath.

    • Copy the source code into VuGen using the “View Source” option.
      1) Click “View Source” in the upper right corner when hovering mouse over the code
      2) In the popup window, Select All text and Copy it into the clipboard
      3) Paste into VuGen, at the end of the Vuser_Init() action.

      Note: To use the code in the Vuser_Init() action, you must paste the code BEFORE the vuser_init() { .. } function.

    • lr_save_string( “\”XYZ\”,\”MPQ\”,\”RSD\””, “lrvar” );

      lr_replace(“lrvar”, “\”,\””, “&” );

      lr_output_message(“Notify: %s”, lr_eval_string(“{lrvar}”) );

  5. Hi Kim,

    using
    lr_save_string(lr_eval_string(“{pRecVersBIN}”),”LRParam”);
    lr_replace( “LRParam”, “\\”, “\\\\” );
    lr_output_message( “%s”, lr_eval_string(“{LRParam}”) );
    I am getting
    Action.c(1045): Notify: Parameter Substitution: parameter “pRecVersBIN” = “\x8dŽ\x16\x07\x00”
    Action.c(1045): Notify: Saving Parameter “LRParam = \x8dŽ\x16\x07”.
    vuser_init.c(194): Notify: Parameter Substitution: parameter “LRParam” = “\x8dŽ\x16\x07”
    vuser_init.c(199): Notify: Saving Parameter “LRParam = \x8dŽ\x16\x07”.
    Action.c(1047): Notify: Parameter Substitution: parameter “LRParam” = “\x8dŽ\x16\x07”
    Action.c(1047): Ž
    Not changing “\” to “\\”.

    Can you please help?
    Thanks

    • You are trying to replace inside a BINARY string, 5 bytes in length. The data is $8D $8E $16 $07 $00 (numbers in HEX).

      The ‘\x8d’ means that the character decimal number 142 (or $8D in HEX) is in that place. The \x is just the way C shows that there is a binary character there (see http://en.wikipedia.org/wiki/Hexadecimal for details).

      You can not replace the \ in the string since it does not exist in the string. You can have a look at http://www.ascii-code.com/ for details on what the characters really are.

      Why would you want to replace the \ characters anyway? The output you seek with the replace statement shown would be ‘\\x8dŽ\\x16\\x07’ which still is gibberish and absolutely not at all in line with what the original data was. Also note that the last \x00 is completely removed as C terminates strings with a $00 (ASCII NULL) character, you lose the last character when you handle it as a string.

  6. Hi Kim,

    In the web_custom_request(“SubmitChanges”, I have this value that needs to be correlated and I capture this in binary but in the “Submit Changes” it comes with “\\” instead of “\” what I get from correlation,
    \rRecordVersion\\x8D\\xC0\\x15\\x07\\x00`\r”(This is in script). I don’t know how to handle this. Can you help pls?

    Thanks,

    Syed

    • From offline discussion I’m posting here the solution to the question:

      When LR captures data as binary with web_reg_save_param() it is shown in the log window as \x?? format, where the ?? are the ASCII table hex number of a character. Example: \x30 (Dec 48) is the same as character zero. See here for more info on ASCII character numbers: http://www.ascii-code.com/.

      There is a a special case for NULL or ASCII Character 0. This can be represented with a double \\ in a string. Example:

      web_reg_save_param(“pRecVersBIN”,
      “LB/IC=\rRecordVersion”,
      “RB/BIN=\\x00”, // Note the DOUBLE \\ to represent ASCII Character 0 (also known as NULL character)
      LAST);

      In addition the double \\ notation can be used in custom POST requests when the body parameter is BodyBinary. Example:

      web_custom_request(“x”,
      “URL=http://127.0.0.1/bin/post.php”,
      “Method=POST”,
      “Mode=HTTP”,
      “Body=a=”,
      “BodyBinary=\\x40\\x40”, // We also mix several body types. Here we insert two @@
      “Body={pRecVersBIN}”, // that are concatenated together. Insert saved binary data.
      “BodyBinary=\\x40\\x40”, // to produce one big body. Here we insert two @@
      LAST );

      This will produce the following POST data, given that the pRecVersBIN param contains the following binary data: “\x8D\x8E\x16\x07” (raw hex dump):

      00000000h: 40 40 8D 8E 16 07 40 40 ; @@Ž..@@

      So even if LR in all instances shows \\x?? or \x?? notation of the binary stuff, the actual data sent in the POST is still the raw bytes.

  7. I was struggling for a couple of days getting past some character replacement until I saw this. I tried it and it was working in minutes. Many thanks for sharing this. Keep up the good work. Im now so relieved I can move on with the scripting.

  8. Works like a charm .. Kim add a like button to your pages and I would keep clicking them.. ur base 64 encoding also was very useful…

  9. Hi, I like to know the solution for below query.

    wrsp captured the session value in the format…d9add5a1\x2D0\x3A0..and it is in the script like d9add5a1-0:0
    Can you help me out how I can convert ASCII code into binary format. Thanks alot

    • You can search for and replace binary characters by using the \x prefix.

      Example: lr_replace(“MyString”, “\x20”, “\x32”);

      This will replace all SPACE characters with the 0 (zero) character in the MyString parameter.

  10. Hi!

    I am new to LR.
    I am facing a similar problem. A variable contains space which when converted to URL by web_convert_param, replaces spaces(” “) by “+” but in the actual url contains “%20” in place of spaces. Hnece I want to replace “+” by “%20” . When I copied the above program in Vuser_init below error comes on compiling:

    vuser_init.c (25): syntax error; found `{‘ expecting `;’
    vuser_init.c (25): skipping `{‘
    vuser_init.c (35): undeclared identifier `src’
    vuser_init.c (36): undeclared identifier `from’
    vuser_init.c (37): undeclared identifier `to’
    vuser_init.c (57): operands of = have illegal types `int’ and `pointer to char’
    vuser_init.c (111): illegal return type; found `pointer to char’ expected `int’
    vuser_init.c (143): operands of = have illegal types `pointer to char’ and `int’
    vuser_init.c (154): unrecognized declaration
    vuser_init.c (154): unrecognized declaration
    vuser_init.c (154): warning: empty declaration
    vuser_init.c (155): unrecognized declaration
    c:\\users\\eswabas\\appdata\\local\\temp\\noname8\\\\combined_noname8.c (5): 11 errors, not writing pre_cci.ci

    Can you please help me out with this?

  11. My apologies -third attempt. The problem with the question being posted is that some of the characters I’m using to describe the issue are being converted when uploading.

    I have data being received in a webservice call which has ampersand lt; ampersand gt; and \n (the latter followed by any number of spaces) where I need to have and \n. I’ve had to spell out the ampersand in each case here to have it posted I hope this makes sense to someone.

    • last attempt at posting the original question – I’m not advanced in C and need a find and replace routine which takes the data returned from a webservice and makes it xml format. The data read in is supposed to be xml but has “<” “>” (minus the quotes) and \n where there should be < > and I guess newline. Would the source code at the top of this list be able to do this conversion for me and can anyone help me with some pointers please? Alternatively if anyone knows why what is supposed to be an xml format file would be read in as text in this way?

      • Can you post the RAW XML that you get so I understand what you mean. The search&replace will take care of most of the cases, but I’d need to understand what you need replaced to give you the proper Find and Replace strings for the routine.

  12. Hi,

    Thanks for this. I am getting an error when i try to verify replay, it says “Syntax error on line 47 near “;”” this line is: for ( ;; ) //Loop until no matches are found

    Thanks
    Sean

  13. Hey I have a string that I got from correlation of 2500 characters and i need to replace ” with /”. Please let me know the chnages need to be done in code. A part of string that i got is below:-

    {“Origin”:0,”AlertOrigin”:0,”EntityId”:0,”ParentId”:0,”IsReadyToPublish”:false,”ScenarioSection”:{“Name”:”[New Alert Template]”,”CommonName”:null,”AvailableForQuickPublish”:false,”Description”:null,”IsSystemScenario”:false,”ChannelId”:0},”……

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s