Last active
July 12, 2018 16:33
-
-
Save TheXenocide/23bf89b18e29b4ca35f95207e352f331 to your computer and use it in GitHub Desktop.
Just a quick LINQPad extension method to highlight matched text in a string. Not thoroughly tested, but it seems to be working well for my needs.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
void Main() | |
{ | |
"Testing this neat thing out to see if there is highlighting 123456789 evenly".HighlightStringMatches("th", "esting this", "1", "2", "3", "4", "5", "6", "7", "8", "9").Dump(); | |
} | |
public static class MyExtensions | |
{ | |
public static string HtmlEncode(this string text) | |
{ | |
return HttpUtility.HtmlEncode(text); | |
} | |
private static readonly Color[] HighlightColors = new Color[] { | |
Color.Yellow, | |
Color.Cyan, | |
Color.LightSeaGreen, | |
Color.Magenta, | |
Color.DimGray, | |
Color.Lavender, | |
Color.Salmon, | |
Color.Orchid, | |
Color.PeachPuff, | |
Color.SteelBlue, | |
Color.Violet | |
}; | |
private class HighlightableTextFragment | |
{ | |
public Color? Highlight { get; set; } | |
public int StartIndex { get; set; } | |
public int Length { get; set; } | |
public int LastIndex | |
{ | |
get { return StartIndex + Length; } | |
} | |
public object GetDumpFragment(string fullText) | |
{ | |
var text = fullText.Substring(StartIndex, Length) ?? ""; // null-coalesce just in case overlaps cause a 0 length substring (which returns null) | |
return Highlight != null | |
? Util.RawHtml("<span style=\"color: black; background:" + System.Drawing.ColorTranslator.ToHtml(Color.FromArgb(Highlight.Value.ToArgb())) + "\">" + | |
text.HtmlEncode() + | |
"</span>" | |
) // using raw html here because text selection looks a little different with the Highlight function and I had played with controlling FG color too | |
: text; | |
} | |
} | |
public static object HighlightStringMatches(this string fullText, params string[] strings) | |
{ | |
return HighlightRegexMatches(fullText, strings.Select(s => Regex.Escape(s)).ToArray()); | |
} | |
public static object HighlightRegexMatches(this string fullText, params string[] regexes) | |
{ | |
return HighlightRegexMatches(fullText, regexes.Select(r => new Regex(r)).ToArray()); | |
} | |
public static object HighlightRegexMatches(this string fullText, params Regex[] regexes) | |
{ | |
var allMatches = regexes.Zip(Enumerable.Range(0, regexes.Length), (i, j) => new | |
{ | |
TermIndex = j, | |
Regex = i | |
}).SelectMany(rx => rx.Regex.Matches(fullText).Cast<Match>().Select(m => new | |
{ | |
TermIndex = rx.TermIndex, | |
StartIndex = m.Index, | |
Length = m.Length | |
})).OrderBy(m => m.StartIndex); | |
if (allMatches.Any()) | |
{ | |
List<HighlightableTextFragment> fragments = new List<HighlightableTextFragment>(); | |
foreach (var match in allMatches) | |
{ | |
if (fragments.Count == 0) | |
{ | |
if (match.StartIndex != 0) | |
{ | |
fragments.Add(new HighlightableTextFragment() | |
{ | |
StartIndex = 0, | |
Length = match.StartIndex | |
}); | |
} | |
fragments.Add(new HighlightableTextFragment() | |
{ | |
Highlight = HighlightColors[match.TermIndex], | |
StartIndex = match.StartIndex, | |
Length = match.Length | |
}); | |
} | |
else | |
{ | |
HighlightableTextFragment continued = null; | |
var previous = fragments[fragments.Count - 1]; | |
if (previous.LastIndex > match.StartIndex) | |
{ | |
if (previous.LastIndex > match.StartIndex + match.Length) | |
{ | |
continued = new HighlightableTextFragment() | |
{ | |
Highlight = previous.Highlight, | |
StartIndex = match.StartIndex + match.Length, | |
Length = previous.LastIndex - (match.StartIndex + match.Length) | |
}; | |
} | |
previous.Length = match.StartIndex - previous.StartIndex; | |
} | |
else if (previous.LastIndex < match.StartIndex) | |
{ | |
fragments.Add(new HighlightableTextFragment() | |
{ | |
StartIndex = previous.LastIndex, | |
Length = match.StartIndex - previous.LastIndex | |
}); | |
} | |
fragments.Add(new HighlightableTextFragment() | |
{ | |
Highlight = HighlightColors[match.TermIndex], | |
StartIndex = match.StartIndex, | |
Length = match.Length | |
}); | |
if (continued != null) fragments.Add(continued); | |
} | |
} | |
var last = fragments[fragments.Count - 1]; | |
if (last.LastIndex < fullText.Length) fragments.Add(new HighlightableTextFragment() | |
{ | |
StartIndex = last.LastIndex, | |
Length = fullText.Length - last.LastIndex | |
}); | |
return Util.WordRun(false, fragments.Select(f => f.GetDumpFragment(fullText))); | |
} | |
else | |
{ | |
return fullText; | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment