replace(char) String function? [SOLVED]

On 25/10/2014 at 10:47, xxxxxxxx wrote:

User Information:
Cinema 4D Version:   13 
Platform:   Windows  ;   
Language(s) :     C++  ;

---------
Hi,
Is there a replace function for strings in the SDK?

I have a string like this: Foo%20Foo%20Foo%20/index.html
And I wat to convert it to this: Foo Foo Foo/index.html

The %20 stuff is coming from my htmlViewerCallback() SDK function.
And I'd like to convert it to a regular Filename format with spaces.
Replacing every %20 instance with a space.

-ScottA

On 25/10/2014 at 16:03, xxxxxxxx wrote:

I had to do this same thing recently, and couldn't find such a function in the SDK. You can write one yourself though, it's very easy.

Steve

On 25/10/2014 at 16:27, xxxxxxxx wrote:

I was afraid of that Steve,
I ended up using the STL regex to do it. Because the RegularExprParser in the SDK seem to be far too primitive to do this without writing a ton of code.
I'd prefer to stick to using the SDK as much as possible. But that R.E.P. class really needs some TLC by Maxon.

void htmlViewerCallback(void *user_data, const String &url, LONG encoding, void *reserved)  
{  
  //Prints the path to the webpage in the console when the hyperlink is clicked on  
  //This takes some time because it fetches the webpage..that's why a callback function is required  
  //GePrint(url);  
  
  //The url string value returned is formatted with %20 for spaces. And forward leaning slashes  
  //So this is how to convert it to a normal Windows file path type string result  
  
  CHAR buffer[1024];  
  
  //First convert the forward leaning slashes to backwards leaning slashes  
  url.GetCString(buffer, sizeof(buffer));  
  std::string stlurl = buffer;  
  std::tr1::regex rx1("/");  
  std::string replacement1 = "\\";  
  std::string result1 = std::tr1::regex_replace(stlurl, rx1, replacement1);  
  
  //Next replace the %20 instances with spaces  
  std::string stlur2 = result1;  
  std::tr1::regex rx2("%(..)");  
  std::string replacement2 = " ";  
  std::string result = std::tr1::regex_replace(stlur2, rx2, replacement2);  
  String c4dURLresult = result.c_str();  
  
  //Now we need to delete the file:/// crap at the start of the url string  
  for(LONG i=0; i<8; i++)  
  {  
      c4dURLresult _= '\n';  
  }  
  
  //The url converted to a regular filename  
  GePrint(c4dURLresult);  
}

-ScottA
_

On 26/10/2014 at 01:33, xxxxxxxx wrote:

Hi Scott,

I'm not too sure about your code.

First of all, I have to do strange things to get std::string and regex through the compiler within the SDK. Mainly because regex demands to have exceptions. To work around this with a define or (even worse) by enabling exceptions for the SDK is dangerous. The SDK disables exception handling, as handling exceptions (and potential cleanup needs due to an exception) is tricky in a multithreaded environment.

I really disadvise to enable exception handling for your plugins. If you really need to, you will have to understand exactly what is happening and be aware of the thread context your functions are called in.

Next, probably just caused by posting this as an example, is the for loop in the end. It simply doesn't do what the comment says it would. Furthermore, it it's not iterating (c4dURLresult is constant). It's simply replacing the string eight times with a linefeed.

Finally, I don't understand, why you need regular expressions at all in this case.
Here's my attempt on your htmlViewerCallback():

void htmlViewerCallback(void *user_data, const String &url, LONG encoding, void *reserved)
{
  String sResult = url;
  LONG   iPos;
  //Prints the path to the webpage in the console when the hyperlink is clicked on
  //This takes some time because it fetches the webpage..that's why a callback function is required
  GePrint("Before: " + sResult);
  // First we need to delete the file:/// crap at the start of the url string
  if (!sResult.ComparePart("file:///", 8, 0)) {
    sResult.Delete(0, 8);
  }
  // Then convert the forward leaning slashes to backwards leaning slashes
  while (sResult.FindFirst("/", &iPos, 0)) {
    sResult.Delete(iPos, 1);
    sResult.Insert(iPos, "\\");
  }
  // Lastly replace the %20 instances with spaces
  while (sResult.FindFirst("\%20", &iPos, 0)) {
    sResult.Delete(iPos, 3);
    sResult.Insert(iPos, " ");
  }
  GePrint("After: " + sResult);
}

This is just a quick example and certainly could be done faster and more generic.

On 26/10/2014 at 04:12, xxxxxxxx wrote:

Please note that the replacement of the forward slash to a back slash in an url is only necessary on non-Unix systems (-> Windows).

If you apply this conversion (of the slashes) to a Unix compatible system (OS X, Linux) then you create a wrong Filename that won't work.

Best regards,

Wilfried

On 26/10/2014 at 04:14, xxxxxxxx wrote:

Andreas is absolutely right, just keep it simple and forget all that regular expression stuff. It doesn't need it for something so very simple.

On 26/10/2014 at 07:08, xxxxxxxx wrote:

My code works just fine for me. And I didn't need to enable exceptions. Or do anything special for regex to work Andreas.
All I did was #include <regex>. And then wrote the code I posted.
I'm still using VS2010 most of time. I don't know if that matters?

Thanks for posting your version though.

-ScottA

On 26/10/2014 at 07:13, xxxxxxxx wrote:

Scott,
I think this matters, as it may not warn about this with older compiler versions (or if you are lucky the old standard lib doesn't use exceptions for regex).
I can only stress my words, I disadvise to use any external libraries which may need or make use of exceptions. We won't be able to help, if you run into problems with such stuff.
Of course there are cases you will need to use external libraries, I fully understand. All I'm saying, I wouldn't do so, if there's no need for it.

On 26/10/2014 at 07:17, xxxxxxxx wrote:

One question to the community, as Scott says, his code is working as posted. How does the following loop help to eliminate the "file:///" prefix, I don't get it?

for(LONG i=0; i<8; i++) {
  c4dURLresult = '\n';
}

On 26/10/2014 at 07:17, xxxxxxxx wrote:

Ok. Thanks.
I'm very comfortable using the STL in my code but...

Originally posted by xxxxxxxx

I'd prefer to stick to using the SDK as much as possible. __

-ScottA

On 26/10/2014 at 07:19, xxxxxxxx wrote:

😉

On 26/10/2014 at 11:40, xxxxxxxx wrote:

Actually. That for() loop does NOT work properly.
The C4D console reports that it does...But it's evil. It's lying to us. Evil Smile
The C4D console does not show the correct carriage returns, like the VS console does (it removes them).
I'm glad you mentioned it Andreas. Because I would have wondered what the heck was going on later when I used the returned string.

This should work better when using the STL regex class.
But I'm going to use your SDK based code instead.

  
#include <regex>  
void htmlViewerCallback(void *user_data, const String &url, LONG encoding, void *reserved)  
{  
  //Prints the path to the webpage in the console when the hyperlink is clicked on  
  //This takes some time because it fetches the webpage..that's why a callback function is required  
  //GePrint(url);  
  
  //The url string value returned is formatted with %20 for spaces. And forward leaning slashes  
  //So this is how to convert it to a normal Windows file path type string result  
  
  CHAR buffer[1024];  
  
  //First convert the forward leaning slashes to backwards leaning slashes  
  url.GetCString(buffer, sizeof(buffer));  
  std::string stlurl = buffer;  
  std::tr1::regex rx1("/");  
  std::string replacement1 = "\\";  
  std::string result1 = std::tr1::regex_replace(stlurl, rx1, replacement1);  
  
  //Next replace the %20 instances with spaces  
  std::string stlur2 = result1;  
  std::tr1::regex rx2("%(..)");  
  std::string replacement2 = " ";  
  std::string result = std::tr1::regex_replace(stlur2, rx2, replacement2);  
  
  //Now we need to delete the file:/// crap at the start of the url string      
  for(int i=0; i<8; i++)  
  {  
      result.erase(result.begin());  
  }  
  
  //The url converted to a regular filename  
  String c4dURLresult = result.c_str();  
  GePrint(c4dURLresult);  
}

Thanks for the help guys,
-ScottA

On 26/10/2014 at 13:09, xxxxxxxx wrote:

I marked this solved.
Yet, I want to emphasize Wilfried's post. You'll have to care for more systems but Windows.

On 27/10/2014 at 09:13, xxxxxxxx wrote:

Btw, there's std::string::substr() and String::SubStr(). Easier to read and by far more efficient than
erasing the first character in a for loop.