Skip to content

Instantly share code, notes, and snippets.

@TheXenocide
Last active July 12, 2018 16:33
Show Gist options
  • Save TheXenocide/23bf89b18e29b4ca35f95207e352f331 to your computer and use it in GitHub Desktop.
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.
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