MayHeCome/Assets/Plugins/Febucci/Text Animator/Scripts/Runtime/Parsing/TextParser.cs
2024-12-18 17:55:34 +08:00

119 lines
4.5 KiB
C#

using System.Text;
namespace Febucci.UI.Core.Parsing
{
/// <summary>
/// Handles text parsing and rich text tags recognition
/// </summary>
public static class TextParser
{
public static string ParseText(string text, params TagParserBase[] rules)
{
if(rules == null || rules.Length == 0)
{
UnityEngine.Debug.LogWarning("No rules were provided to parse the text. Skipping");
return text;
}
//PS At the moment, only for avoiding fails on domain reload
//and multiple tags on different text sets
foreach (var rule in rules)
{
rule.Initialize();
}
/*
P.S. Calculating tags etc. is done inside this single method (and not split for each rule etc.)
so that the text is only parsed once, and not multiple times for each rule - improving performance
*/
StringBuilder result = new StringBuilder();
// create an array of character from text
var characters = text.ToCharArray();
int len = characters.Length;
bool foundTag;
string fullTag;
bool allowParsing = true;
//For every character in text
for(int textIndex = 0, realTextIndex = 0; textIndex < len; textIndex++)
{
foundTag = false;
//searches for noparse first
if (characters[textIndex] == '<')
{
int closeIndex = text.IndexOf('>', textIndex + 1);
if(closeIndex>0)
{
int tagLength = closeIndex - textIndex + 1;
void PasteTagToText()
{
foundTag = true;
result.Append(fullTag);
textIndex = closeIndex;
}
fullTag = text.Substring(textIndex, tagLength);
switch (fullTag.ToLower())
{
case "<noparse>":
allowParsing = false;
PasteTagToText();
break;
case "</noparse>":
allowParsing = true;
PasteTagToText();
break;
}
}
}
if (allowParsing && !foundTag)
{
foreach (var rule in rules) //tries rich tags
{
if (characters[textIndex] == rule.startSymbol)
{
for (int endIndex = textIndex + 1; endIndex < len && !foundTag; endIndex++)
{
//If there's an opening symbol, skips since it's a new tag
if (characters[endIndex] == rule.startSymbol)
break;
if (characters[endIndex] == rule.endSymbol)
{
// Gets the length of the tag
int tagLength = endIndex - textIndex - 1;
if (tagLength == 0) //Skips empty tag
break;
if (rule.TryProcessingTag(
text.Substring(textIndex + 1, tagLength),
tagLength,
ref realTextIndex,
result,
textIndex))
{
foundTag = true;
textIndex = endIndex; //Tag processed, skips others
break;
}
}
}
}
}
}
if (!foundTag)
{
result.Append(characters[textIndex]);
realTextIndex++;
}
}
return result.ToString();
}
}
}