I have a user-settable text, where the default one is [Log in] or [register] to view the content.
What I need, is to wrap the two words in square brackets in their respective links. But first, I need to check that the user didn't change this default text, in other words that they kept the square brackets. I won't go in great lengths in checking this. Just the existence of two sets of square brackets is enough. If that's the case, then I'll assume that the first link is for the login page, and the second is for the register-an-account page...
So, the if below does the job for me:
if ( preg_match( '/\[(.*?)\].*\[(.*?)\]/', $text ) )

Then, inside the if, my plan was to perform a str_replace() with two arrays like this:
$text = str_replace( array( '[', ']', '[', ']' ), array( '%1$s', '%2$s', '%3$s', '%4$s' ), $text );

But this doesn't work the way I thought it would. I thought that since the two arrays have equal number of elements it'd do a 1-on-1 search and replace, meaning that it would turn the text to %1$sLog in%2$s or %3$sregister%4$s to view the content, whereas it turned to %1$sLog in%2$s or %1$sregister%2$s to view the content.
Why is that? If that's not the proper way to do that (which obviously isn't), what should I do instead?
Any help would be very much appreciated. TIA.

Strange behavior of str_replace
Try using preg_replace with your same pattern (with additional capture):
$text = preg_replace('/\[(.*?)\](.*)\[(.*?)\]/', '%1$s$1%2$s$2%3$s$3%4$s', $text); 

which produces
%1$sLog in%2$s or %3$sregister%4$s to view the content

The str_replace does not work the way you intended - the first array is an array of needles which has no sense of position so the second set of [] are duplicate needles in your case.
See tester
