$re = '/<ref\s+((?:group|follow|extends)\s*=(?:(?!name\s*=)[\s\S])*)?name\s*=\s*(?:"\s*([^"](?:(?!\s*\/>|\s*"\s*>|\s+(?:group|follow|extends)).)*?)\s*"|\'\s*([^\'"](?:(?!\s*\/>|\s*\'>|\s+(?:group|follow|extends)).)*?)\s*\'|([^"](?:(?!\s*\/>|\s*>|\s+(?:group|follow|extends)).)*))(\s+(?:group|follow|extends)\s*=(?:(?!\s*\/>|"\s*>|\'\s*>)[\s\S])*)*\s*(?:(\/)|)>/m';
$str = '<ref name=Test1 /><ref name=Test2 />
<ref name=Bad 1 /><ref name=Bad 2 />
<ref name="Test 3"/>
<ref name="Test 4" />
<ref name=Test5>Foo</ref>
<ref name="Test 6">Foo</ref>
<ref
name=Test7>Foo
</ref>
<ref
name = Test8 >
Foo
</ref>
<ref name = Test9 > Foo </ref>
<ref
name="Test 10">Foo
</ref>
<ref
name = "Test 11" >
Foo
</ref>
<ref name = Test12 > Foo </ref>
<ref name = Test13 />
<ref name = "Test 14" />
<ref
name = Test15 />
<ref
name =
"Test 16"
/>
<ref
name
=
Test17
/>
<ref
name
=
"Test 18"
/>
<ref name="Test/19" />
==A heading==
<ref name = "Test/20" />
<ref name = "Test 21"/>
<ref name = "Test / 22"/>
<ref name = "Test > 23"/>
<ref name="Te>st/ 23.1"/>
<ref
name
="
Test 24
"/>
<ref name=\'Test/ 25\' />
<ref name=\'Test/ 26\'> Foo </ref>
<ref name=\'Te>st/ 27\' />
<ref name = " Test 28 " >Foo</ref>
<ref name=\'Test "29"\' /> - This one is expected to produce invalid XML "\'Test "29"\'"; surprisingly, MW can parse it anyway for a case this simple, but not if there\'s a space within the interior-most quotes: "\'Test "2 9"\'"
<ref name = "Test 30" >
<ref name = "Test 31">
<ref name = "Test 32" />
<ref name = "Test 33"/>
<ref name = Test34 >
<ref name = Test35>
<ref name = Test36 />
<ref name = Test37/>
<ref name = " Test 38 "/>
<ref name = " Test 39 " />
<ref name=\'Test 40\'/>
<ref name=AAA/>
<ref name="BBB AAA BBB" />
<ref name="This "isjustnot" valid"/> - This one is expected to produce invalid XML "This "isjustnot" valid"; surprisingly, MW can parse it anyway for a case this simple, but not if there\'s a space within the interior-most quotes: "This "is just not" valid".
<ref name="This \'actually is\' valid"/>
<ref name=\'But this "is also" a problem\' /> (or will be after our " substitution)
<ref name=apostrophe\'s />
<ref name="more apostrophe\'s" />
<ref name=\'this\'s bad, but we can fix it!\' />
<ref name=\'this is okay\'/>
<ref name="\'this is dumb\'"/>
<ref name="this is \'less\' dumb" />
<ref name="what about \'this case\'"/>
<ref name="\'or this\' one" />
<ref name="foo" group="bar"/>
<ref name="foo" group="bar" />
<ref group="bar" name="foo" />
<ref name=\'foo\' group=\'bar\'/>
<ref name=\'foo\' group=\'bar\' />
<ref group=\'bar\' name=\'foo\' />
<ref name=foo group=bar/>
<ref name=foo group=bar />
<ref group=bar name=foo/>
<ref name="foo" follow="bar" />
<ref name=\'foo\' follow=\'bar\'/>
<ref name=foo follow=bar/>
<ref name="foo" extends="bar" />
<ref name=\'foo\' extends=\'bar\'/>
<ref name=foo extends=bar/>
<ref name=\'foo\' group="bar" extends=baz follow="quux quux" />
<ref group="bar" name=\'foo\' extends=baz follow="quux quux" />
<ref group="bar" extends=baz name=\'foo\' follow="quux quux" />
<ref group="bar" extends=baz follow="quux quux" name=\'foo\' />
<ref group="bar" extends=baz name=foo follow="quux quux" />
<ref group="bar" extends=baz name="foo\'s foo" follow="quux quux" />
<ref group="bar\'s > / bar" extends=baz name=\'foos > / foo\' follow="quux quux" />
<ref group=
"bar\'s > / bar"
extends=
baz
name=
\'
foos > / foo
\'
follow=
"quux > quux"
/>
<ref name="foos > / foo" group="bar\'s > / bar" extends=baz follow="quux quux"/>
<ref
name =
\'
foos > / foo
\'
group =
"bar\'s > / bar"
extends
=baz
follow
="
quux quux
"
/>
<ref name="foos > / foo" group="bar\'s > / bar" extends=baz follow=\'quux quux\'/>
';
$subst = "<ref $1name=\"$2$3$4\"$5${6:+ /:}>";
$result = preg_replace($re, $subst, $str);
echo "The result of the substitution is ".$result;
Please keep in mind that these code samples are automatically generated and are not guaranteed to work. If you find any syntax errors, feel free to submit a bug report. For a full regex reference for PHP, please visit: http://php.net/manual/en/ref.pcre.php