[^?] means every character, except the question mark.
* means zero or more of the characters in front of it.
So, [^?]* means a string of zero or more characters, not containing a question mark.
\? means a question mark. It is escaped, because the question mark has a meaning in the regular expression language.
. means any kind of character
So, \?.* means a question mark, followed by zero or more characters.
() copies the part between the parenthesis for later usage. $1 for the first (), $2 for the second (), etc.
? means the character in front of it is optional. Hence, the escaping of the question mark earlier.
()? means the part between the parenthesis being optional, while copying it for later usage.
So, [^?]*(\?.*)? means a string of zero or more characters, not containing a question mark, optionally followed by a string starting with a question mark. This optional string starting with a question mark is placed after /index.php
So, /file.txt becomes /index.php, /file.txt?foo=bar becomes /index.php?foo=bar.
Yeah, I know, regular expressions look like crypto magic at first sight. But once you learn how it works, it's so easy and powerful. The vim editor allows regular expressions for search & replace. Soooo powerful!!
Regular Expressions Cheat Sheet [www.cheatography.com]