194 lines
7.6 KiB
C#
194 lines
7.6 KiB
C#
using System.Text.RegularExpressions;
|
||
using ZelWiki.Engine.Function;
|
||
using ZelWiki.Models;
|
||
|
||
namespace ZelWiki.Engine
|
||
{
|
||
/// <summary>
|
||
///
|
||
/// </summary>
|
||
public class WikifierLite
|
||
{
|
||
public static string Process(string? unprocessedText)
|
||
{
|
||
unprocessedText = unprocessedText?.Trim() ?? string.Empty;
|
||
if (string.IsNullOrWhiteSpace(unprocessedText))
|
||
{
|
||
return string.Empty;
|
||
}
|
||
|
||
for (var i = 0; i < 100; i++)
|
||
{
|
||
var processedMatches = false;
|
||
var matchStore = new Dictionary<string, string>();
|
||
|
||
var content = new WikiString(unprocessedText);
|
||
TransformEmoji(content, matchStore);
|
||
TransformLinks(content, matchStore);
|
||
TransformMarkup(content, matchStore);
|
||
|
||
foreach (var match in matchStore)
|
||
{
|
||
processedMatches = true;
|
||
content.Replace(match.Key, match.Value);
|
||
}
|
||
|
||
if (!processedMatches)
|
||
{
|
||
break;
|
||
}
|
||
|
||
unprocessedText = content.ToString();
|
||
}
|
||
|
||
return unprocessedText;
|
||
}
|
||
|
||
private static string StoreMatch(Dictionary<string, string> matchStore, string value)
|
||
{
|
||
var guid = Guid.NewGuid().ToString();
|
||
matchStore.Add(guid, value);
|
||
return guid;
|
||
}
|
||
|
||
private static void TransformEmoji(WikiString pageContent, Dictionary<string, string> matchStore)
|
||
{
|
||
var rgx = new Regex(@"(%%.+?%%)", RegexOptions.IgnoreCase);
|
||
var matches = WikiUtility.OrderMatchesByLengthDescending(rgx.Matches(pageContent.ToString()));
|
||
foreach (var match in matches)
|
||
{
|
||
string key = match.Value.Trim().ToLower().Trim('%');
|
||
int scale = 100;
|
||
|
||
var parts = key.Split(',');
|
||
if (parts.Length > 1)
|
||
{
|
||
key = parts[0]; //Image key;
|
||
scale = int.Parse(parts[1]); //Image scale.
|
||
}
|
||
|
||
key = $"%%{key}%%";
|
||
|
||
var emoji = GlobalConfiguration.Emojis.FirstOrDefault(o => o.Shortcut == key);
|
||
|
||
if (GlobalConfiguration.Emojis.Exists(o => o.Shortcut == key))
|
||
{
|
||
if (scale != 100 && scale > 0 && scale <= 500)
|
||
{
|
||
var emojiImage =
|
||
$"<img src=\"/file/Emoji/{key.Trim('%')}?Scale={scale}\" alt=\"{emoji?.Name}\" />";
|
||
pageContent.Replace(match.Value, StoreMatch(matchStore, emojiImage));
|
||
}
|
||
else
|
||
{
|
||
var emojiImage = $"<img src=\"/file/Emoji/{key.Trim('%')}\" alt=\"{emoji?.Name}\" />";
|
||
pageContent.Replace(match.Value, StoreMatch(matchStore, emojiImage));
|
||
}
|
||
}
|
||
else
|
||
{
|
||
pageContent.Replace(match.Value, StoreMatch(matchStore, string.Empty));
|
||
}
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 转换单行和多行的基本标记,如粗体、斜体、下划线等
|
||
/// </summary>
|
||
/// <param name="pageContent"></param>
|
||
/// <param name="matchStore"></param>
|
||
private static void TransformMarkup(WikiString pageContent, Dictionary<string, string> matchStore)
|
||
{
|
||
var symbols = WikiUtility.GetApplicableSymbols(pageContent.Value);
|
||
|
||
foreach (var symbol in symbols)
|
||
{
|
||
var sequence = new string(symbol, 2);
|
||
var escapedSequence = Regex.Escape(sequence);
|
||
|
||
var rgx = new Regex(@$"{escapedSequence}(.*?){escapedSequence}", RegexOptions.IgnoreCase);
|
||
var orderedMatches = WikiUtility.OrderMatchesByLengthDescending(rgx.Matches(pageContent.ToString()));
|
||
foreach (var match in orderedMatches)
|
||
{
|
||
string body = match.Value.Substring(sequence.Length, match.Value.Length - sequence.Length * 2);
|
||
|
||
var markup = symbol switch
|
||
{
|
||
'~' => $"<strike>{body}</strike>",
|
||
'*' => $"<strong>{body}</strong>",
|
||
'_' => $"<u>{body}</u>",
|
||
'/' => $"<i>{body}</i>",
|
||
'!' => $"<mark>{body}</mark>",
|
||
_ => body,
|
||
};
|
||
|
||
pageContent.Replace(match.Value, StoreMatch(matchStore, markup));
|
||
}
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 转换链接,这些链接可以是内部Wiki链接或外部链接
|
||
/// </summary>
|
||
/// <param name="pageContent"></param>
|
||
/// <param name="matchStore"></param>
|
||
private static void TransformLinks(WikiString pageContent, Dictionary<string, string> matchStore)
|
||
{
|
||
//解析外部链接 [[http://test.net]].
|
||
var rgx = new Regex(@"(\[\[http\:\/\/.+?\]\])", RegexOptions.IgnoreCase);
|
||
var matches = WikiUtility.OrderMatchesByLengthDescending(rgx.Matches(pageContent.ToString()));
|
||
foreach (var match in matches)
|
||
{
|
||
var keyword = match.Value.Substring(2, match.Value.Length - 4).Trim();
|
||
var args = FunctionParser.ParseRawArgumentsAddParenthesis(keyword);
|
||
|
||
if (args.Count > 1)
|
||
{
|
||
pageContent.Replace(match.Value, StoreMatch(matchStore, $"<a href=\"{args[0]}\">{args[1]}</a>"));
|
||
}
|
||
else
|
||
{
|
||
pageContent.Replace(match.Value, StoreMatch(matchStore, $"<a href=\"{args[0]}\">{args[0]}</a>"));
|
||
}
|
||
}
|
||
|
||
//解析外部链接. [[https://test.net]].
|
||
rgx = new Regex(@"(\[\[https\:\/\/.+?\]\])", RegexOptions.IgnoreCase);
|
||
matches = WikiUtility.OrderMatchesByLengthDescending(rgx.Matches(pageContent.ToString()));
|
||
foreach (var match in matches)
|
||
{
|
||
var keyword = match.Value.Substring(2, match.Value.Length - 4).Trim();
|
||
var args = FunctionParser.ParseRawArgumentsAddParenthesis(keyword);
|
||
|
||
if (args.Count == 1)
|
||
{
|
||
pageContent.Replace(match.Value, StoreMatch(matchStore, $"<a href=\"{args[0]}\">{args[1]}</a>"));
|
||
}
|
||
else if (args.Count > 1)
|
||
{
|
||
pageContent.Replace(match.Value, StoreMatch(matchStore, $"<a href=\"{args[0]}\">{args[0]}</a>"));
|
||
}
|
||
}
|
||
|
||
//解析内部链接 [[AboutUs|About Us]].
|
||
rgx = new Regex(@"(\[\[.+?\]\])", RegexOptions.IgnoreCase);
|
||
matches = WikiUtility.OrderMatchesByLengthDescending(rgx.Matches(pageContent.ToString()));
|
||
foreach (var match in matches)
|
||
{
|
||
var keyword = match.Value.Substring(2, match.Value.Length - 4);
|
||
var args = FunctionParser.ParseRawArgumentsAddParenthesis(keyword);
|
||
|
||
if (args.Count == 1)
|
||
{
|
||
pageContent.Replace(match.Value,
|
||
StoreMatch(matchStore, $"<a href=\"{GlobalConfiguration.BasePath}/{args[0]}\">{args[0]}</a>"));
|
||
}
|
||
else if (args.Count > 1)
|
||
{
|
||
pageContent.Replace(match.Value,
|
||
StoreMatch(matchStore, $"<a href=\"{GlobalConfiguration.BasePath}/{args[0]}\">{args[1]}</a>"));
|
||
}
|
||
}
|
||
}
|
||
}
|
||
} |