7
I'll start off by saying I checked and checked again that this question should be on topic.
I will also clearly state that this is a tips question about further golfing a certain set of code not a challenge.
I recently answered the following challenge: Scramble words while preserving their outlines:
It is well known that a text can still be read while the innards of its words have been scrambled, as long as their first and last letters plus their overall outlines remain constant. Given a printable Ascii+Newline text, scramble each word according to these rules:
Scrambling must be (pseudo) random.
A word is a sequence of the Latin characters, A through Z.
Only initial letters will ever be uppercase.
The first and last letters must stay untouched.
When scrambling, only letters within one of the following groups may exchange places:
acemnorsuvwxz
bdfhkl
gpqy
it
j
(stays in place)
My answer is in C# and coming in, currently, at 394 bytes:
namespace System{using Text.RegularExpressions;using Linq;s=>Regex.Replace(s,@"[A-Za-z](([acemnorsu-xz])|([bdfhkl])|([gpqy])|([it]))*?[a-z]?\b",m=>{var a=m.Value.ToCharArray();for(int i=1,j;++i<6;){var c=m.Groups[i].Captures;var n=c.Cast<Capture>().Select(p=>p.Index-m.Index).ToList();foreach(Capture p in c){a[j=n[new Random().Next(n.Count)]]=p.Value[0];n.Remove(j);}}return new string(a);});}
I think there's room for golfing in the Linq statement and foreach
loop at least.
Can this code be further golfed down?
Off the bat,
(i|t)
is shorter than([it])
. And if you order your character classes differently, you can probably replace the really long one with[a-z]
because all the other letters will have already been covered by earlier groups. I'm also not sure your code works correctly for words containingj
. As far as I can tell those words wouldn't be matched (instead of just leaving thej
untouched). – Martin Ender – 2017-05-15T11:22:14.770@MartinEnder It wouldn't have handled the
j
correctly, good spot on that and with the re-ordering the regex is a bit shorter so that helps too! I'm not the best with regex if you hadn't realised... – TheLethalCoder – 2017-05-15T11:32:00.223Since the input is limited to ASCII, you can also use
\p{L}
for[A-Za-z]
. – Martin Ender – 2017-05-15T11:35:45.357@MartinEnder I'd seen that suggestion on other answers and forgotten about it! Regex is now
\p{L}(([bdfhkl])|([gpqy])|(i|t)|(j)|([a-z]))*?[a-z]?\b
– TheLethalCoder – 2017-05-15T11:44:22.177If you put the first group before the last one, it can be shortened to
[bdf-l]
, becausegij
have already been taken care of. – Martin Ender – 2017-05-15T11:48:37.300@MartinEnder All that has saved 10 bytes so far:
\p{L}(([gpqy])|(i|t)|(j)|([bdf-l])|([a-z]))*?[a-z]?\b
. Can you add an answer with the improvements so far? – TheLethalCoder – 2017-05-15T12:07:28.417