import Foundation
let pattern = #"<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*(?:(\/)|)>"#
let regex = try! NSRegularExpression(pattern: pattern, options: .anchorsMatchLines)
let testString = #"""
<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'/>
"""#
let stringRange = NSRange(location: 0, length: testString.utf16.count)
let substitutionString = #"<ref $1name="$2$3$4"$5${6:+ /:}>"#
let result = regex.stringByReplacingMatches(in: testString, range: stringRange, withTemplate: substitutionString)
print(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 Swift 5.2, please visit: https://developer.apple.com/documentation/foundation/nsregularexpression