行首标点检测功能

using System;
using UnityEngine;
using UnityEngine.UI;
using System.Text;
using System.Text.RegularExpressions;


[XLua.WhiteList]
public sealed class LText : Text
{
    //是否跳过检测行首标点
    private bool SkipMoveSymbol = false;

    private readonly string matchPunctuation = @"\p{P}";

    private readonly string specialSymbol = "…"; //省略号特殊处理,不能被截断
    //private readonly string exceptPunctuation = @"(\<|\>|\[|\])";

    //private readonly string exceptPunctuation = @"(\<|\[|\{)";
    private readonly string openingBrackets = @"(\<|\[|\{|\(|《)";

    //private readonly string endingBrackets = @"(\>|\]|\})";
    private Vector2 m_RectTransformSize;
    private TextGenerationSettings m_GenerationSettings;

    private StringBuilder m_TextStrBuilder;

    private StringBuilder TextStrBuilder
    {
        get { return m_TextStrBuilder ?? (m_TextStrBuilder = new StringBuilder()); }
    }

    public override string text
    {
        get { return m_Text; }
        set
        {
            if (string.IsNullOrEmpty(value))
            {
                if (string.IsNullOrEmpty(m_Text))
                    return;
                m_Text = "";
                SetVerticesDirty();
            }
            else
            {
                if (!Application.isPlaying)
                {
                    return;
                }

                if (!inParsing)
                {  
                    m_Text = ParseTextStr(value);
                    SetVerticesDirty();
                    SetLayoutDirty();
                }
            }
        }
    }
    
    protected override void OnRectTransformDimensionsChange()
    {
        // 更新行数或其他逻辑文本的尺寸发生了变化
        //组件上挂载的有ContentSizeFilter的时候计算行数会有问题,因此再次调用一下
        m_Text = ParseTextStr(m_Text);
        SetVerticesDirty();
        SetLayoutDirty();
    }
    
    public override void SetVerticesDirty()
    {
        base.SetVerticesDirty();
        m_RectTransformSize = rectTransform.rect.size;
        m_GenerationSettings = GetGenerationSettings(m_RectTransformSize);
    }
    private bool inParsing = false;

    //解析文本,看是否需要换行
    private string ParseTextStr(string textStr)
    {
        if (!SkipMoveSymbol)
        {
            m_RectTransformSize = rectTransform.rect.size;
            m_GenerationSettings = GetGenerationSettings(m_RectTransformSize);

            inParsing = true;
            textStr = moveLineLast(textStr);
            inParsing = false;
        }

        return textStr;
    }

    #region 同步检测行首标点,要点在于while循环内重复调用PopulateWithErrors,获取tempTextGenerator.lines;

    //private static readonly TextGenerator  sTempTextGenerator = new TextGenerator();
    private bool CheckMove(ref string tempStr)
    {
        //sTempTextGenerator.PopulateWithErrors(m_OutputText, m_GenerationSettings,gameObject);
        
        cachedTextGenerator.PopulateWithErrors(tempStr, m_GenerationSettings, gameObject);

        int changeIndex = -1;
        int lengthStr = tempStr.Length;
        for (int i = 1; i < cachedTextGenerator.lines.Count; i++)
        {
            int startMatchIndex = cachedTextGenerator.lines[i].startCharIdx;
            if (startMatchIndex >= lengthStr)
            {
                break;
            }

            int preLineStartCharIdx = cachedTextGenerator.lines[i - 1].startCharIdx;
            int preLineEndMatchIndex = cachedTextGenerator.lines[i].startCharIdx - 1;
            int curLineStartCharIdx = cachedTextGenerator.lines[i].startCharIdx;

            int preLineCharCount = curLineStartCharIdx - preLineStartCharIdx;
            if (preLineCharCount == 1)
            {
                //如果上一行只有一个字符,则跳过
                continue;
            }

            if (preLineEndMatchIndex < 0 || preLineEndMatchIndex >= tempStr.Length)
            {
                continue;
            }

            bool endStrMark = MatchLineEndStr(tempStr[preLineEndMatchIndex].ToString());
            if (endStrMark)
            {
                //上一行行尾是成对符号的开始字符
                changeIndex = preLineEndMatchIndex;
                break;
            }

            string matchStr = tempStr[startMatchIndex].ToString();
            //判断该行行首是否是符号
            bool isMark = MatchPunctuation(matchStr);
            if (isMark)
            {
                string preMatchStr = tempStr[preLineEndMatchIndex].ToString();
                bool isPreLineEndMark = MatchPunctuation(preMatchStr);
                if (preMatchStr.Equals("\n"))
                {
                    MDebug.LogError("换行符和标点连用,策划看下是不是不符合版署要求:" + tempStr);
                    continue;
                    //isPreLineEndMark = true;
                }

                bool isCurSpecial = matchStr.Equals(specialSymbol);
                if (isCurSpecial)
                {
                    if (isPreLineEndMark)
                    {
                        //上一行末尾是省略号的前一半,多拉一个字符下来
                        changeIndex = FindMatchIndex(tempStr, preLineEndMatchIndex - 1);
                        break;
                    }
                    //如果当前符号是省略号

                    //判断省略号是否被截断
                    bool isCompletion = false;
                    int nextIndex = curLineStartCharIdx + 1;
                    if (nextIndex < lengthStr)
                    {
                        string nextStr = tempStr[nextIndex].ToString();
                        if (nextStr.Equals(specialSymbol))
                        {
                            //省略号完整
                            isCompletion = true;
                        }
                    }

                    if (isCompletion)
                    {
                        if (isPreLineEndMark)
                        {
                            //上一行末尾是符号
                            continue;
                        }
                    }
                }
                else
                {
                    //不是省略号,但上一行末尾是标点,应该是标点连用的错误
                    if (isPreLineEndMark)
                    {
                        //上一行末尾是省略号的前一半,多拉一个字符下来
                        changeIndex = FindMatchIndex(tempStr, preLineEndMatchIndex - 1);
                        break;
                    }
                }

                changeIndex = preLineEndMatchIndex;

                //颜色富文本处理
                int subStartIndex = preLineStartCharIdx;
                int subLength = curLineStartCharIdx - preLineStartCharIdx;
                string str = tempStr.Substring(subStartIndex, subLength);

                MatchCollection richStrMatch =
                    Regex.Matches(str, ".(</color>|<color=#\\w{6}>|" + matchPunctuation + ")+$");
                if (richStrMatch.Count > 0)
                {
                    string richStr = richStrMatch[0].ToString();
                    int length = richStr.Length;
                    changeIndex = curLineStartCharIdx - length;
                    break;
                }

                if (changeIndex >= 0)
                {
                    break;
                }
            }
        }

        if (changeIndex >= 0)
        {
            TextStrBuilder.Clear();
            TextStrBuilder.Append(tempStr);
            TextStrBuilder.Insert(changeIndex, '\n');
            tempStr = TextStrBuilder.ToString();
            return true;
        }

        return false;
    }

    //找到非标点的index
    private int FindMatchIndex(string _tempStr, int _preIndex)
    {
        int whileCount = 0;
        while (_preIndex > 0)
        {
            string preMatchStr = _tempStr[_preIndex].ToString();
            bool result = MatchPunctuation(preMatchStr);
            if (!result)
            {
                return _preIndex;
            }

            --_preIndex;

            ++whileCount;

            if (whileCount >= 1)
            {
                MDebug.LogError(_tempStr + "多个标点连用!!!");
                return -1;
            }
        }

        return -1;
    }


    //判断是否是符号
    private bool MatchPunctuation(string matchStr)
    {
        bool isMark = Regex.IsMatch(matchStr, matchPunctuation);
        bool isOpenBracket = Regex.IsMatch(matchStr, openingBrackets);
        if (isMark && !isOpenBracket)
        {
            //如果是富文本用到的,则忽略
            return true;
        }

        return false;
    }

    //判断行尾是否是成对字符的开始字符
    private bool MatchLineStartStr(string matchStr)
    {
        bool isMark = Regex.IsMatch(matchStr, openingBrackets);
        return isMark;
    }

    //判断行尾是否是成对字符的开始字符
    private bool MatchLineEndStr(string matchStr)
    {
        bool isMark = Regex.IsMatch(matchStr, openingBrackets);
        return isMark;
    }


    private string moveLineLast(string str)
    {
        string originStr = str;
        bool flag = true;
        int maxWhileCount = 50;
        int whileCount = 0;
        while (flag)
        {
            if (whileCount >= maxWhileCount)
            {
                return originStr;
            }

            flag = CheckMove(ref str);
            whileCount++;
        }

        return str;
    }

    #endregion
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值