mirror of
https://github.com/Tyrrrz/DiscordChatExporter.git
synced 2026-02-15 00:03:38 -07:00
Make StringPart readonly struct
This commit is contained in:
parent
2a223599f9
commit
964317dac0
|
|
@ -1,20 +1,10 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Text.RegularExpressions;
|
|
||||||
|
|
||||||
namespace DiscordChatExporter.Core.Markdown.Internal
|
namespace DiscordChatExporter.Core.Markdown.Internal
|
||||||
{
|
{
|
||||||
internal static class Extensions
|
internal static class Extensions
|
||||||
{
|
{
|
||||||
public static StringPart Shrink(this StringPart stringPart, int newStartIndex, int newLength) =>
|
|
||||||
new StringPart(stringPart.Target, newStartIndex, newLength);
|
|
||||||
|
|
||||||
public static StringPart Shrink(this StringPart stringPart, int newStartIndex) =>
|
|
||||||
stringPart.Shrink(newStartIndex, stringPart.EndIndex - newStartIndex);
|
|
||||||
|
|
||||||
public static StringPart Shrink(this StringPart stringPart, Capture capture) =>
|
|
||||||
stringPart.Shrink(capture.Index, capture.Length);
|
|
||||||
|
|
||||||
public static IEnumerable<ParsedMatch<T>> MatchAll<T>(this IMatcher<T> matcher, StringPart stringPart,
|
public static IEnumerable<ParsedMatch<T>> MatchAll<T>(this IMatcher<T> matcher, StringPart stringPart,
|
||||||
Func<StringPart, T> fallbackTransform)
|
Func<StringPart, T> fallbackTransform)
|
||||||
{
|
{
|
||||||
|
|
@ -23,7 +13,7 @@ namespace DiscordChatExporter.Core.Markdown.Internal
|
||||||
while (currentIndex < stringPart.EndIndex)
|
while (currentIndex < stringPart.EndIndex)
|
||||||
{
|
{
|
||||||
// Find a match within this segment
|
// Find a match within this segment
|
||||||
var match = matcher.Match(stringPart.Shrink(currentIndex, stringPart.EndIndex - currentIndex));
|
var match = matcher.Match(stringPart.Slice(currentIndex, stringPart.EndIndex - currentIndex));
|
||||||
|
|
||||||
// If there's no match - break
|
// If there's no match - break
|
||||||
if (match == null)
|
if (match == null)
|
||||||
|
|
@ -32,7 +22,7 @@ namespace DiscordChatExporter.Core.Markdown.Internal
|
||||||
// If this match doesn't start immediately at current index - transform and yield fallback first
|
// If this match doesn't start immediately at current index - transform and yield fallback first
|
||||||
if (match.StringPart.StartIndex > currentIndex)
|
if (match.StringPart.StartIndex > currentIndex)
|
||||||
{
|
{
|
||||||
var fallbackPart = stringPart.Shrink(currentIndex, match.StringPart.StartIndex - currentIndex);
|
var fallbackPart = stringPart.Slice(currentIndex, match.StringPart.StartIndex - currentIndex);
|
||||||
yield return new ParsedMatch<T>(fallbackPart, fallbackTransform(fallbackPart));
|
yield return new ParsedMatch<T>(fallbackPart, fallbackTransform(fallbackPart));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -46,7 +36,7 @@ namespace DiscordChatExporter.Core.Markdown.Internal
|
||||||
// If EOL wasn't reached - transform and yield remaining part as fallback
|
// If EOL wasn't reached - transform and yield remaining part as fallback
|
||||||
if (currentIndex < stringPart.EndIndex)
|
if (currentIndex < stringPart.EndIndex)
|
||||||
{
|
{
|
||||||
var fallbackPart = stringPart.Shrink(currentIndex);
|
var fallbackPart = stringPart.Slice(currentIndex);
|
||||||
yield return new ParsedMatch<T>(fallbackPart, fallbackTransform(fallbackPart));
|
yield return new ParsedMatch<T>(fallbackPart, fallbackTransform(fallbackPart));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -33,8 +33,8 @@ namespace DiscordChatExporter.Core.Markdown.Internal
|
||||||
if (!_regex.IsMatch(stringPart.Target.Substring(0, stringPart.EndIndex), stringPart.StartIndex))
|
if (!_regex.IsMatch(stringPart.Target.Substring(0, stringPart.EndIndex), stringPart.StartIndex))
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
var stringPartShrunk = stringPart.Shrink(match.Index, match.Length);
|
var stringPartMatch = stringPart.Slice(match.Index, match.Length);
|
||||||
return new ParsedMatch<T>(stringPartShrunk, _transform(stringPartShrunk, match));
|
return new ParsedMatch<T>(stringPartMatch, _transform(stringPartMatch, match));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -26,8 +26,8 @@ namespace DiscordChatExporter.Core.Markdown.Internal
|
||||||
|
|
||||||
if (index >= 0)
|
if (index >= 0)
|
||||||
{
|
{
|
||||||
var stringPartShrunk = stringPart.Shrink(index, _needle.Length);
|
var stringPartMatch = stringPart.Slice(index, _needle.Length);
|
||||||
return new ParsedMatch<T>(stringPartShrunk, _transform(stringPartShrunk));
|
return new ParsedMatch<T>(stringPartMatch, _transform(stringPartMatch));
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,8 @@
|
||||||
namespace DiscordChatExporter.Core.Markdown.Internal
|
using System.Text.RegularExpressions;
|
||||||
|
|
||||||
|
namespace DiscordChatExporter.Core.Markdown.Internal
|
||||||
{
|
{
|
||||||
internal class StringPart
|
internal readonly struct StringPart
|
||||||
{
|
{
|
||||||
public string Target { get; }
|
public string Target { get; }
|
||||||
|
|
||||||
|
|
@ -23,6 +25,12 @@
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public StringPart Slice(int newStartIndex, int newLength) => new StringPart(Target, newStartIndex, newLength);
|
||||||
|
|
||||||
|
public StringPart Slice(int newStartIndex) => Slice(newStartIndex, EndIndex - newStartIndex);
|
||||||
|
|
||||||
|
public StringPart Slice(Capture capture) => Slice(capture.Index, capture.Length);
|
||||||
|
|
||||||
public override string ToString() => Target.Substring(StartIndex, Length);
|
public override string ToString() => Target.Substring(StartIndex, Length);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -16,57 +16,57 @@ namespace DiscordChatExporter.Core.Markdown
|
||||||
// Capture any character until the earliest double asterisk not followed by an asterisk
|
// Capture any character until the earliest double asterisk not followed by an asterisk
|
||||||
private static readonly IMatcher<Node> BoldFormattedNodeMatcher = new RegexMatcher<Node>(
|
private static readonly IMatcher<Node> BoldFormattedNodeMatcher = new RegexMatcher<Node>(
|
||||||
new Regex("\\*\\*(.+?)\\*\\*(?!\\*)", DefaultRegexOptions | RegexOptions.Singleline),
|
new Regex("\\*\\*(.+?)\\*\\*(?!\\*)", DefaultRegexOptions | RegexOptions.Singleline),
|
||||||
(p, m) => new FormattedNode(TextFormatting.Bold, Parse(p.Shrink(m.Groups[1]))));
|
(p, m) => new FormattedNode(TextFormatting.Bold, Parse(p.Slice(m.Groups[1]))));
|
||||||
|
|
||||||
// Capture any character until the earliest single asterisk not preceded or followed by an asterisk
|
// Capture any character until the earliest single asterisk not preceded or followed by an asterisk
|
||||||
// Opening asterisk must not be followed by whitespace
|
// Opening asterisk must not be followed by whitespace
|
||||||
// Closing asterisk must not be preceded by whitespace
|
// Closing asterisk must not be preceded by whitespace
|
||||||
private static readonly IMatcher<Node> ItalicFormattedNodeMatcher = new RegexMatcher<Node>(
|
private static readonly IMatcher<Node> ItalicFormattedNodeMatcher = new RegexMatcher<Node>(
|
||||||
new Regex("\\*(?!\\s)(.+?)(?<!\\s|\\*)\\*(?!\\*)", DefaultRegexOptions | RegexOptions.Singleline),
|
new Regex("\\*(?!\\s)(.+?)(?<!\\s|\\*)\\*(?!\\*)", DefaultRegexOptions | RegexOptions.Singleline),
|
||||||
(p, m) => new FormattedNode(TextFormatting.Italic, Parse(p.Shrink(m.Groups[1]))));
|
(p, m) => new FormattedNode(TextFormatting.Italic, Parse(p.Slice(m.Groups[1]))));
|
||||||
|
|
||||||
// Capture any character until the earliest triple asterisk not followed by an asterisk
|
// Capture any character until the earliest triple asterisk not followed by an asterisk
|
||||||
private static readonly IMatcher<Node> ItalicBoldFormattedNodeMatcher = new RegexMatcher<Node>(
|
private static readonly IMatcher<Node> ItalicBoldFormattedNodeMatcher = new RegexMatcher<Node>(
|
||||||
new Regex("\\*(\\*\\*.+?\\*\\*)\\*(?!\\*)", DefaultRegexOptions | RegexOptions.Singleline),
|
new Regex("\\*(\\*\\*.+?\\*\\*)\\*(?!\\*)", DefaultRegexOptions | RegexOptions.Singleline),
|
||||||
(p, m) => new FormattedNode(TextFormatting.Italic, Parse(p.Shrink(m.Groups[1]), BoldFormattedNodeMatcher)));
|
(p, m) => new FormattedNode(TextFormatting.Italic, Parse(p.Slice(m.Groups[1]), BoldFormattedNodeMatcher)));
|
||||||
|
|
||||||
// Capture any character except underscore until an underscore
|
// Capture any character except underscore until an underscore
|
||||||
// Closing underscore must not be followed by a word character
|
// Closing underscore must not be followed by a word character
|
||||||
private static readonly IMatcher<Node> ItalicAltFormattedNodeMatcher = new RegexMatcher<Node>(
|
private static readonly IMatcher<Node> ItalicAltFormattedNodeMatcher = new RegexMatcher<Node>(
|
||||||
new Regex("_([^_]+)_(?!\\w)", DefaultRegexOptions | RegexOptions.Singleline),
|
new Regex("_([^_]+)_(?!\\w)", DefaultRegexOptions | RegexOptions.Singleline),
|
||||||
(p, m) => new FormattedNode(TextFormatting.Italic, Parse(p.Shrink(m.Groups[1]))));
|
(p, m) => new FormattedNode(TextFormatting.Italic, Parse(p.Slice(m.Groups[1]))));
|
||||||
|
|
||||||
// Capture any character until the earliest double underscore not followed by an underscore
|
// Capture any character until the earliest double underscore not followed by an underscore
|
||||||
private static readonly IMatcher<Node> UnderlineFormattedNodeMatcher = new RegexMatcher<Node>(
|
private static readonly IMatcher<Node> UnderlineFormattedNodeMatcher = new RegexMatcher<Node>(
|
||||||
new Regex("__(.+?)__(?!_)", DefaultRegexOptions | RegexOptions.Singleline),
|
new Regex("__(.+?)__(?!_)", DefaultRegexOptions | RegexOptions.Singleline),
|
||||||
(p, m) => new FormattedNode(TextFormatting.Underline, Parse(p.Shrink(m.Groups[1]))));
|
(p, m) => new FormattedNode(TextFormatting.Underline, Parse(p.Slice(m.Groups[1]))));
|
||||||
|
|
||||||
// Capture any character until the earliest triple underscore not followed by an underscore
|
// Capture any character until the earliest triple underscore not followed by an underscore
|
||||||
private static readonly IMatcher<Node> ItalicUnderlineFormattedNodeMatcher = new RegexMatcher<Node>(
|
private static readonly IMatcher<Node> ItalicUnderlineFormattedNodeMatcher = new RegexMatcher<Node>(
|
||||||
new Regex("_(__.+?__)_(?!_)", DefaultRegexOptions | RegexOptions.Singleline),
|
new Regex("_(__.+?__)_(?!_)", DefaultRegexOptions | RegexOptions.Singleline),
|
||||||
(p, m) => new FormattedNode(TextFormatting.Italic, Parse(p.Shrink(m.Groups[1]), UnderlineFormattedNodeMatcher)));
|
(p, m) => new FormattedNode(TextFormatting.Italic, Parse(p.Slice(m.Groups[1]), UnderlineFormattedNodeMatcher)));
|
||||||
|
|
||||||
// Capture any character until the earliest double tilde
|
// Capture any character until the earliest double tilde
|
||||||
private static readonly IMatcher<Node> StrikethroughFormattedNodeMatcher = new RegexMatcher<Node>(
|
private static readonly IMatcher<Node> StrikethroughFormattedNodeMatcher = new RegexMatcher<Node>(
|
||||||
new Regex("~~(.+?)~~", DefaultRegexOptions | RegexOptions.Singleline),
|
new Regex("~~(.+?)~~", DefaultRegexOptions | RegexOptions.Singleline),
|
||||||
(p, m) => new FormattedNode(TextFormatting.Strikethrough, Parse(p.Shrink(m.Groups[1]))));
|
(p, m) => new FormattedNode(TextFormatting.Strikethrough, Parse(p.Slice(m.Groups[1]))));
|
||||||
|
|
||||||
// Capture any character until the earliest double pipe
|
// Capture any character until the earliest double pipe
|
||||||
private static readonly IMatcher<Node> SpoilerFormattedNodeMatcher = new RegexMatcher<Node>(
|
private static readonly IMatcher<Node> SpoilerFormattedNodeMatcher = new RegexMatcher<Node>(
|
||||||
new Regex("\\|\\|(.+?)\\|\\|", DefaultRegexOptions | RegexOptions.Singleline),
|
new Regex("\\|\\|(.+?)\\|\\|", DefaultRegexOptions | RegexOptions.Singleline),
|
||||||
(p, m) => new FormattedNode(TextFormatting.Spoiler, Parse(p.Shrink(m.Groups[1]))));
|
(p, m) => new FormattedNode(TextFormatting.Spoiler, Parse(p.Slice(m.Groups[1]))));
|
||||||
|
|
||||||
// Capture any character until the end of the line
|
// Capture any character until the end of the line
|
||||||
// Opening 'greater than' character must be followed by whitespace
|
// Opening 'greater than' character must be followed by whitespace
|
||||||
private static readonly IMatcher<Node> SingleLineQuoteNodeMatcher = new RegexMatcher<Node>(
|
private static readonly IMatcher<Node> SingleLineQuoteNodeMatcher = new RegexMatcher<Node>(
|
||||||
new Regex("^>\\s(.+)\r?\n?", DefaultRegexOptions),
|
new Regex("^>\\s(.+)\r?\n?", DefaultRegexOptions),
|
||||||
(p, m) => new FormattedNode(TextFormatting.Quote, Parse(p.Shrink(m.Groups[1]))));
|
(p, m) => new FormattedNode(TextFormatting.Quote, Parse(p.Slice(m.Groups[1]))));
|
||||||
|
|
||||||
// Capture any character until the end of the input
|
// Capture any character until the end of the input
|
||||||
// Opening 'greater than' characters must be followed by whitespace
|
// Opening 'greater than' characters must be followed by whitespace
|
||||||
private static readonly IMatcher<Node> MultiLineQuoteNodeMatcher = new RegexMatcher<Node>(
|
private static readonly IMatcher<Node> MultiLineQuoteNodeMatcher = new RegexMatcher<Node>(
|
||||||
new Regex("^>>>\\s(.+)", DefaultRegexOptions | RegexOptions.Singleline),
|
new Regex("^>>>\\s(.+)", DefaultRegexOptions | RegexOptions.Singleline),
|
||||||
(p, m) => new FormattedNode(TextFormatting.Quote, Parse(p.Shrink(m.Groups[1]))));
|
(p, m) => new FormattedNode(TextFormatting.Quote, Parse(p.Slice(m.Groups[1]))));
|
||||||
|
|
||||||
/* Code blocks */
|
/* Code blocks */
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue