Sorry to be thick-headed (read: slow-witted) but I have to ask: why did you SELECT TOP (8000) ROW_NUMBER... when it [seems] to work with TOP (10). Since we're using only the numbers 0-9, I would have figured using a generic "number generator" like SELECTING ROW_NUMBER() ... from a "known" source that would have at least 10 records (like sys.objects), you could skinny down the code and maybe processing as well:
DECLARE @String VARCHAR(8000) = 'ABC12D34E56';
SELECT SUBSTRING(@String, n.[Number], 1)
SELECT TOP (10) ROW_NUMBER()
OVER (ORDER BY [object_id]) AS [Number]
FROM sys.objects) n
WHERE n.[Number] <= LEN(@String)
AND SUBSTRING(@String, n.[Number], 1) LIKE '[0-9]'
ORDER BY n.[Number]
FOR XML PATH(''), TYPE).[value]('.', 'VARCHAR(8000)');
Factoring in inflation, health care, taxes and cost of living, my two cents isn't worth much so I apologize if I missed something. I'll blame the lack of coffee for any oversight on my part.