5评论

Lua中的..替换为StringFormat脚本

薛薛 2018-09-14 1.5k浏览

想免费获取内部独家PPT资料库?观看行业大牛直播?点击加入腾讯游戏学院游戏开发行业精英群711501594

Lua中的..替换为StringFormat脚本


背景:

在对工程进行多语言改造的时候,发现Lua代码中大家通常都是采用 .. 来进行字符串连接的,但这种写法给多语言Key的设置带来了很多不便。例如:

BriefPromptTip.show("主公,如果取消研究会失去研究所花费资源的"..per.."%,是否确定要取消研究?", "确定", nil, function()

由于句中常常需要加入一些变量,会将原有的句子断开成为两句或者更多,如果对前后半句话分别设置一个多语言Key,其语义不完整,对翻译不利。
但如果将其改写为:

BriefPromptTip.show(string.format("主公,如果取消升级会失去升级所花费资源的%s%,是否确定要取消升级?", per), "确定", nil, function()

则翻译同学可以直接在译文文本中沿用%s的设定,进行更灵活准确的翻译。

将 .. 结构替换为string.format结构的工具或者IDE目前我还没有找到,只好自己写脚本进行处理。

基本思路

首先要识别句中包含中文且前后有 .. 的字符串,可以用一个正则来匹配出来

Pattern_CN_Expression = re.compile(r'(?:(\.\.)?\s*("(?:[^"]*[\u4e00-\u9fa5]+[^"]*)+")\s*(\.\.)?)|(?:(\.\.)?\s*(\'(?:[^\']*[\u4e00-\u9fa5]+[^\']*)+\')\s*(\.\.)?)')

这个正则的匹配结果的 [0][1][2] 索引非空,即代表字符串为双引号内的中文,[0][2]标识前后是否有 .. ,若[3][4][5]非空,则代表字符串为单引号内的中文,[3][5]标识前后是否有 .. 。把对应的中文文本存起来,后续的判定将围绕这几个文本展开。

将代码用split按”..” 分割开

判断中文文本在分隔出的字符串中的位置
继续沿用刚才的例子,其第一个分割字符串为:

BriefPromptTip.show("主公,如果取消研究会失去研究所花费资源的"

可以识别到,中文文本在字符串末尾。
将中文文本去掉,替换为

BriefPromptTip.show(string.format(

我们需要时刻记住string.format是否开始了。
继续看第二个分隔出字符串

per

非中文,且它是一个完整的语义块(如何判断完整语义块请参看文末的代码),因此,它一定是作为string.format的一个变量存在的,先记着。
PS:如果非完整语义块,则需要另外处理(后文讨论)。
第三个分割出的字符串为

"%,是否确定要取消研究?", "确定", nil, function()

可以发现,中文字符串位于句首,可以肯定,这是一个string.format的最后一个参数。我们将这里的中文去掉,剩下的部分先暂存起来。

, "确定", nil, function()

将刚才的三个参数组装起来,并将非中文的完整语义块用%s替代,得到如下代码

BriefPromptTip.show(string.format("主公,如果取消升级会失去升级所花费资源的%s%,是否确定要取消升级?"

将完整语义块作为参数附在后面,并用括号结束string.format

BriefPromptTip.show(string.format("主公,如果取消升级会失去升级所花费资源的%s%,是否确定要取消升级?", per)

我们发现,除了这个字符串连接之外,还有刚才暂存的小尾巴,加上之后就组装完成。

BriefPromptTip.show(string.format("主公,如果取消升级会失去升级所花费资源的%s%,是否确定要取消升级?", per), "确定", nil, function()

复杂情况

在刚才阐述的基本思路中,未考虑各种复杂情况。如将例子改为

BriefPromptTip.show(function("主公,如果取消研究会失去研究所花费资源的"..per).."%,是否确定要取消研究?", "确定", nil, function()

这种情况下分割出来的字符串分别为

BriefPromptTip.show(function("主公,如果取消研究会失去研究所花费资源的"
per)
"%,是否确定要取消研究?", "确定", nil, function()

首先按照之前的逻辑,完成一个开头

BriefPromptTip.show(function(string.format(

接着看第二个字符串,显然非完整语义块(多了一个括号),这种情况下,我们需要取出其第一个语义块来(对应函数 !!#9900ff checkFirstBlockOfLine!! 见文末)
得到第一个语义块per后,将后面的括号保存起来,我们叫它小尾巴
由于不完整语义块的存在,我们可以肯定,string.format已经结束了,因为如果后面还有..,则中间的语义块一定是完整的。
因此我们将string.format组装一下

BriefPromptTip.show(function(string.format("主公,如果取消研究会失去研究所花费资源的%s", per))

此时string.format已经结束了,但我们却发现下一个分割字符串的第一个完整语义块居然是满足我们要求的中文(前后至少有一处 .. )。
我们需要 !!#ff0000 往前回溯!! 一个 !!#ff0000 完整的语义块!! ,用于和此字符串做连接。
同理,获得字符串最后一个完整语义块的函数 !!#9900ff checkLastBlockOfLine!! 见文末。
回溯得到的完整语义块为:

function(string.format("主公,如果取消研究会失去研究所花费资源的%s", per))

将这两个东西组装成string.format (具体的实现是把这两个东西用..连接起来,通过 !!#ff0000 递归!! 解决)

string.format("%s%,是否确定要取消研究? ", function(string.format("主公,如果取消研究会失去研究所花费资源的%s", per)))

组装原则依然是:中文文本先互相拼起来,置于最前,其他语义块作为参数用%s替代,列举在后面。

def checkFirstBlockOfLine(line):
    """
    获得字符串第一个代码语义块,并判断是否是赋值语句
    :param line:
    :return:
    """
    if "return " in line:
        line = line.replace("return ", '')
    stack = []
    singleQuote = False
    doubleQoute = False
    isAssignment = False
    for i in range(len(line)):
        char = line[i]
        if char == '=' and len(stack) == 0:  # 赋值语句
            isAssignment = True
        if char == "'":
            singleQuote = not singleQuote
        elif char == '"':
            doubleQoute = not doubleQoute
        if not singleQuote and not doubleQoute:
            if char == "(" or char == "[" or char == "{":
                stack.append(char)
            else:
                if char == ")" and (len(stack) == 0 or stack.pop() != "("):
                    # print("Error")
                    return line[0:i], isAssignment
                if char == "]" and (len(stack) == 0 or stack.pop() != "["):
                    # print("Error")
                    return line[0:i], isAssignment
                if char == "}" and (len(stack) == 0 or stack.pop() != "{"):
                    # print("Error")
                    return line[0:i], isAssignment
                elif char == "," or (char == "." and i + 1 < len(line) and line[i + 1] == "."):
                    if len(stack) == 0:
                        return line[0:i], isAssignment

    if singleQuote or doubleQoute:
        print("Quote Error")
    if len(stack) is not 0:
        return False
    return line[0:], isAssignment
def checkLastBlockOfLine(line):
    """
    获得字符串最后一个代码语义块
    :param line:
    :return:
    """
    if "return " in line:
        line = line.replace("return ", '')
    stack = []
    singleQuote = False
    doubleQoute = False
    for j in range(len(line)):
        i = len(line) - j - 1
        char = line[i]
        if char == "'":
            singleQuote = not singleQuote
        elif char == '"':
            doubleQoute = not doubleQoute
        if not singleQuote and not doubleQoute:
            if char == ")" or char == "]" or char == "}":
                stack.append(line[i])
            else:
                if char == "(" and (len(stack) == 0 or stack.pop() != ")"):
                    # print("Error")
                    return line[i + 1:]
                if char == "[" and (len(stack) == 0 or stack.pop() != "]"):
                    # print("Error")
                    return line[i + 1:]
                if char == "{" and (len(stack) == 0 or stack.pop() != "}"):
                    # print("Error")
                    return line[i + 1:]
                elif char == "," or line[i] == "=" or (char == "." and i - 1 >= 0 and line[i - 1] == "."):
                    if len(stack) == 0:
                        return line[i + 1:]

    if singleQuote or doubleQoute:
        print("Quote Error")
    if len(stack) is not 0:
        return False
    return line

完整代码

import re

Pattern_CN_Expression = re.compile(r'(?:(\.\.)?\s*("(?:[^"]*[\u4e00-\u9fa5]+[^"]*)+")\s*(\.\.)?)|(?:(\.\.)?\s*(\'(?:[^\']*[\u4e00-\u9fa5]+[^\']*)+\')\s*(\.\.)?)')


def ChangeConcatToStringFormat(luaLineContent):
    """
    单行代码处理
    :param key_prefix: Key前缀,用于构造完整Key
    :param luaLineContent:
    :return:
    """
    global LineLog, Current_key_index

    luaLineContent = RemoveCommentInLine(luaLineContent)

    # 按正则表达式取出含中文的单独字符串
    LineLog += "【中文字符串】"
    CN_Findall_Results = Pattern_CN_Expression.findall(luaLineContent)
    CN_Strs = []
    if CN_Findall_Results:
        for cn_str in CN_Findall_Results:
            # 判断用的是单引号还是双引号、前后是否有点点
            if cn_str[1] != '':
                isDotBefore = cn_str[0] == ".."
                isDotAfter = cn_str[2] == ".."
                if isDotBefore or isDotAfter:
                    CN_Strs.append((cn_str[1], "DoubleQuote", isDotBefore, isDotAfter))
                    LineLog += "[" + cn_str[1] + "]"
            if cn_str[4] != '':
                isDotBefore = cn_str[3] == ".."
                isDotAfter = cn_str[5] == ".."
                if isDotBefore or isDotAfter:
                    CN_Strs.append((cn_str[4], "SingleQuote", isDotBefore, isDotAfter))
                    LineLog += "[" + cn_str[4] + "]"

    # 将代码内容用..Split开
    LineLog += "【按..Split结果】"
    LindSplitDots_Results = luaLineContent.split("..")
    Splits = []
    for spd in LindSplitDots_Results:
        tmp = spd.rstrip('\n').strip(' \t')
        Splits.append(tmp)
        LineLog += "[" + tmp + "]"
    BeforeVars_NonChinese = []  # 在第一个中文字符串出现之前的,被左右..分割的变量
    BeforeString = ''  # 在SPL中中文前面的半段文字
    CNStrUsedIndex = 0
    Strings = []
    StringFormatVars = []  # stringformat的变量
    EndString = ''  # 在SPL中中文后面的半段文字
    isFormatBegin = False  # 一个stringformat是否已开始
    ErrorLog = ""
    AssemblyLine = ""  # 最终拼装代码
    BeforeSPLs = []  # 之前的SPL块
    beforeVars_TraceBack = []  # 回溯过的代码语义块记录,要从BeforeVars中删除他们
    FoundOneMatch = False

    # # 一些特例处理
    # if ":format" in luaLineContent:
    #     ErrorLog += "文本含:format,有复杂语句"
    #     return key_prefix, luaLineContent, "", ErrorLog, CNStrUsedIndex  # 报异常退出

    i = 0
    while i < len(Splits):
        SPL = Splits[i]
        isNeedBeforeSPLappend = True
        isCNInSPL = False
        for j in range(CNStrUsedIndex, len(CN_Strs)):  # 匹配过了就不再找了,避免重复字符串
            CN, QuoteType, isDotBefore, isDotAfter = CN_Strs[j]
            CN_pure = ""  # 纯中文不带引号
            if QuoteType == "DoubleQuote":
                CN_pure = CN.strip("\"")
            elif QuoteType == "SingleQuote":
                CN_pure = CN.strip("\'")

            if CN == SPL:  # SPL正好是CN
                FoundOneMatch = True
                isCNInSPL = True
                CNStrUsedIndex += 1
                if not isFormatBegin:  # 不在StringFormat中
                    if len(BeforeSPLs) != 0:
                        beforeVarsHere = []
                        BeforeString = TraceBackAWord(BeforeString, BeforeSPLs, beforeVars_TraceBack, beforeVarsHere)  # 往前回溯若干个语义块
                        isFormatBegin = True
                        Strings.append("string.format(\"")
                        for m in range(len(beforeVarsHere)):
                            Strings.append("%s")
                        Strings.append(CN_pure)
                        StringFormatVars += beforeVarsHere
                    else:
                        isFormatBegin = True
                        Strings.append("string.format(\"")
                        Strings.append(CN_pure)
                else:
                    Strings.append(CN_pure)  # 如果已经碰到中文,且现在在StringFormat中,直接添加内容
                break
            elif CN in SPL:  # SPL包含CN
                FoundOneMatch = True
                isCNInSPL = True

                # 统计SPL中有几个CN,以便回溯
                before_CNStrUsedIndex = CNStrUsedIndex
                for k in range(CNStrUsedIndex, len(CN_Strs)):
                    CN_tmp, _, _, _ = CN_Strs[k]
                    if CN_tmp in SPL:
                        CNStrUsedIndex += 1
                CNStrUsedIndex_Increase = CNStrUsedIndex - before_CNStrUsedIndex

                if not isFormatBegin:  # 如果碰到包含中文的SPL,但不在StringFormat中
                    if SPL.rindex(CN) + len(CN) == len(SPL):  # 中文在SPL尾部,正常开始StringFormat
                        isFormatBegin = True
                        BeforeString = SPL.replace(CN, '')  # 该SPL去除中文后剩下的部分
                        Strings.append("string.format(\"")
                        Strings.append(CN_pure)
                    elif SPL.index(CN) == 0:  # 中文在SPL头部
                        if isDotBefore and len(BeforeSPLs) != 0:
                            isFormatBegin = True

                            beforeVarsHere = []
                            BeforeString = TraceBackAWord(BeforeString, BeforeSPLs, beforeVars_TraceBack, beforeVarsHere)  # 往前回溯若干个语义块
                            Strings.append("string.format(\"")
                            for m in range(len(beforeVarsHere)):
                                Strings.append("%s")
                            Strings.append(CN_pure)
                            StringFormatVars += beforeVarsHere
                            EndString = SPL.replace(CN, '')

                            # 令上一个format结束
                            AssemblyLine, BeforeString, EndString, isFormatBegin = AStringFormatFinish(StringFormatVars, BeforeSPLs, BeforeString, BeforeVars_NonChinese,
                                                                                                       EndString, Strings, isFormatBegin, beforeVars_TraceBack)
                            SPL = AssemblyLine
                            Splits.remove(Splits[i])
                            Splits.insert(i, SPL)
                            CNStrUsedIndex -= CNStrUsedIndex_Increase
                            i -= 1
                            isNeedBeforeSPLappend = False
                            AssemblyLine = ''
                        else:
                            ErrorLog += "中文在SPL头部且前面没有.."
                            return luaLineContent, "ERROR", ErrorLog, CNStrUsedIndex  # 报异常退出
                    else:  # 中文在SPL中间,保留原样
                        ErrorLog += "中文在中间,可能有函数调用1"
                else:  # 如果已经碰到包含中文的SPL,且已经开始format
                    if SPL.rindex(CN) + len(CN) == len(SPL):  # 中文在SPL尾部
                        temp_SPL = SPL
                        if not checkFirstBlockOfLine(temp_SPL):  # 如果向后判定取不出第一个完整的语义块,则加入到后一个SPL中
                            if i < len(Splits) - 1:
                                temp_SPL = temp_SPL + ".." + Splits[i + 1]
                                Splits.remove(Splits[i])
                                Splits.remove(Splits[i])
                                Splits.insert(i, temp_SPL)
                                i -= 1
                                CNStrUsedIndex -= CNStrUsedIndex_Increase
                                isNeedBeforeSPLappend = False
                                break
                            else:
                                ErrorLog += "意外的情况!原代码语法不完整1"
                                return luaLineContent, "", ErrorLog, CNStrUsedIndex  # 报异常退出
                        else:  # 如果能取出第一个完整的语义块,则分割出来
                            first_SPL = checkFirstBlockOfLine(SPL)[0]
                            if first_SPL != "":
                                temp_SPL = SPL.replace(first_SPL, "")
                                Splits[i] = temp_SPL
                                Splits.insert(i, first_SPL)
                                i -= 1
                                CNStrUsedIndex -= CNStrUsedIndex_Increase
                                isNeedBeforeSPLappend = False
                                break
                            else:
                                EndString = SPL
                                beforeVarsHere = []
                                BeforeString = TraceBackAWord(BeforeString, BeforeSPLs, beforeVars_TraceBack, beforeVarsHere)  # 往前回溯若干个语义块
                                # 令上一个format结束
                                AssemblyLine, BeforeString, EndString, isFormatBegin = AStringFormatFinish(StringFormatVars, BeforeSPLs, BeforeString, BeforeVars_NonChinese,
                                                                                                           EndString, Strings, isFormatBegin, beforeVars_TraceBack)
                                Splits.remove(Splits[i])
                                Splits.insert(i, AssemblyLine)
                                CNStrUsedIndex -= CNStrUsedIndex_Increase
                                i -= 1
                                isNeedBeforeSPLappend = False
                                AssemblyLine = ''
                    elif SPL.index(CN) == 0:  # 中文在头部,正常结束
                        Strings.append(CN_pure)
                        EndString = SPL.replace(CN, '')
                    else:  # 中文在中间
                        if not checkFirstBlockOfLine(SPL):  # 如果向后判定取不出第一个完整的语义块,则加入到后一个SPL中
                            if i < len(Splits) - 1:
                                temp_SPL = SPL + ".." + Splits[i + 1]
                                Splits.remove(Splits[i])
                                Splits.remove(Splits[i])
                                Splits.insert(i, temp_SPL)
                                i -= 1
                                CNStrUsedIndex -= CNStrUsedIndex_Increase
                                isNeedBeforeSPLappend = False
                                break
                        else:  # 如果能取出第一个完整的语义块,则分割出来
                            first_SPL = checkFirstBlockOfLine(SPL)[0]
                            if first_SPL != "":
                                subKey, first_SPL, sub_SPL, subErrorLog, CNStrUsedIndex_Sub = ChangeConcatToStringFormat(first_SPL)  # 递归调用
                                Splits.insert(i + 1, SPL.replace(first_SPL, ""))
                                # 修改SPL为子对象递归替换结果,并回退一次循环
                                Splits[i] = sub_SPL
                                CNStrUsedIndex -= CNStrUsedIndex_Increase
                                i -= 1
                                isNeedBeforeSPLappend = False
                            else:
                                EndString = SPL
                break
        if not isCNInSPL:
            if isFormatBegin:  # 如果不包含中文但已经开始format了,说明是表达式,按%s替换
                if not checkFirstBlockOfLine(SPL):  # 如果向后判定取不出第一个完整的语义块,则加入到后一个SPL中
                    if i < len(Splits) - 1:
                        temp_SPL = SPL + ".." + Splits[i + 1]
                        Splits.remove(Splits[i])
                        Splits.remove(Splits[i])
                        Splits.insert(i, temp_SPL)
                        continue
                else:  # 如果能取出第一个完整的语义块,则分割出来
                    first_SPL = checkFirstBlockOfLine(SPL)[0]
                    if first_SPL != "":
                        Strings.append("%s")
                        StringFormatVars.append(first_SPL)
                        isNeedBeforeSPLappend = False
                        if first_SPL != SPL:
                            Splits.insert(i + 1, SPL.replace(first_SPL, ""))
                    else:
                        EndString = SPL
                        beforeVarsHere = []
                        BeforeString = TraceBackAWord(BeforeString, BeforeSPLs, beforeVars_TraceBack, beforeVarsHere)  # 往前回溯若干个语义块
                        # 令上一个format结束
                        AssemblyLine, BeforeString, EndString, isFormatBegin = AStringFormatFinish(StringFormatVars, BeforeSPLs, BeforeString, BeforeVars_NonChinese,
                                                                                                   EndString, Strings, isFormatBegin, beforeVars_TraceBack)
                        SPL = AssemblyLine
                        Splits.remove(Splits[i])
                        Splits.insert(i, SPL)
                        if Pattern_CN_Expression.match(checkLastBlockOfLine(SPL)):
                            i -= 1
                        AssemblyLine = ''
            else:
                BeforeVars_NonChinese.append(SPL)  # 如果不包含中文但之前还未format了,按原始记录

        if (isNeedBeforeSPLappend):
            BeforeSPLs.append(SPL)

        i += 1
    AssemblyLine, _, _, _ = AStringFormatFinish(StringFormatVars, BeforeSPLs, BeforeString, BeforeVars_NonChinese, EndString, Strings, isFormatBegin, beforeVars_TraceBack)
    LineLog += "【文本替换结果】" + AssemblyLine

    return luaLineContent, AssemblyLine, ErrorLog, CNStrUsedIndex


def TraceBackAWord(BeforeString, BeforeSPLs, beforeVars, beforeVarsHere):
    """
    往前回溯查找是否有可以连接在一起的字符串或等价语义块
    """
    strList = []
    while len(BeforeSPLs) != 0:
        beforeSPL = BeforeSPLs.pop()  # 往前一个SPL
        beforeVar = checkLastBlockOfLine(beforeSPL)  # 取其最后一个语义块(用于当成字符串,写在StringFormat后面作为变量)
        if not beforeVar:  # 如果前面一个SPL里不是完整的代码块,继续向前回溯
            beforeVars.append(beforeSPL)
            tmp = BeforeSPLs.pop()
            beforeSPL = tmp + ".." + beforeSPL
            beforeVars.append(tmp)
            BeforeSPLs.append(beforeSPL)  # 和上一个SPL合并后入栈
            continue
        elif checkLastBlockOfLine(beforeSPL).strip() == beforeSPL.strip():  # 如果前面一个SPL里就是完整的语义,整个作为字符串,且继续向前回溯
            strList.append(beforeVar)
        else:  # 如果前面一个SPL里最后可以取出完整代码块,只回溯它本身
            strList.append(beforeVar)
            BeforeString = beforeSPL.replace(beforeVar, '')
            break
    while len(strList) != 0:
        tmp = strList.pop()
        beforeVars.append(tmp)
        beforeVarsHere.append(tmp)
    return BeforeString


def AStringFormatFinish(StringFormatVars, BeforeSPLs, BeforeString, BeforeVars_NonChinese, EndString, Strings, isFormatBegin, beforeVars_TraceBack):
    """
    string.format 装配
    """
    AssemblyLine = ''
    if len(Strings) == 0 and len(StringFormatVars) == 0 and len(BeforeVars_NonChinese) == 0:
        for BeforeSPL in BeforeSPLs:
            AssemblyLine += BeforeSPL
    if len(StringFormatVars) == 0 and len(BeforeSPLs) == 0 and BeforeString == "" and len(BeforeVars_NonChinese) == 0 and EndString == "" and len(Strings) == 0:
        return AssemblyLine, BeforeString, EndString, isFormatBegin
    # 为format做结尾
    for BeforeVar_NonChinese in BeforeVars_NonChinese:
        isUsed = False
        for beforeVar_TraceBack in beforeVars_TraceBack:
            if beforeVar_TraceBack in BeforeVar_NonChinese:
                if BeforeVar_NonChinese.strip().rindex(beforeVar_TraceBack.strip()) + len(beforeVar_TraceBack.strip()) == len(BeforeVar_NonChinese.strip()):  # 如果被回溯过了
                    isUsed = True
                    break
        if not isUsed:
            AssemblyLine += BeforeVar_NonChinese + " .. "
            if BeforeVar_NonChinese in BeforeSPLs:
                BeforeSPLs.remove(BeforeVar_NonChinese)
    BeforeVars_NonChinese.clear()
    AssemblyLine += BeforeString
    BeforeString = ""
    if len(Strings) != 0 and len(StringFormatVars) != 0:
        for str in Strings:
            AssemblyLine += str
        AssemblyLine += "\""
        for AVar in StringFormatVars:
            AssemblyLine += ", " + AVar
        AssemblyLine += ')'
        Strings.clear()
        StringFormatVars.clear()
    AssemblyLine += EndString
    EndString = ""
    isFormatBegin = False
    AssemblyLine = AssemblyLine.rstrip(" .. ")
    beforeVars_TraceBack.clear()
    return AssemblyLine, BeforeString, EndString, isFormatBegin


def checkFirstBlockOfLine(line):
    """
    获得字符串第一个代码语义块,并判断是否是赋值语句
    :param line:
    :return:
    """
    if "return " in line:
        line = line.replace("return ", '')
    stack = []
    singleQuote = False
    doubleQoute = False
    isAssignment = False
    for i in range(len(line)):
        char = line[i]
        if char == '=' and len(stack) == 0:  # 赋值语句
            isAssignment = True
        if char == "'":
            singleQuote = not singleQuote
        elif char == '"':
            doubleQoute = not doubleQoute
        if not singleQuote and not doubleQoute:
            if char == "(" or char == "[" or char == "{":
                stack.append(char)
            else:
                if char == ")" and (len(stack) == 0 or stack.pop() != "("):
                    # print("Error")
                    return line[0:i], isAssignment
                if char == "]" and (len(stack) == 0 or stack.pop() != "["):
                    # print("Error")
                    return line[0:i], isAssignment
                if char == "}" and (len(stack) == 0 or stack.pop() != "{"):
                    # print("Error")
                    return line[0:i], isAssignment
                elif char == "," or (char == "." and i + 1 < len(line) and line[i + 1] == "."):
                    if len(stack) == 0:
                        return line[0:i], isAssignment

    if singleQuote or doubleQoute:
        print("Quote Error")
    if len(stack) is not 0:
        return False
    return line[0:], isAssignment


def checkLastBlockOfLine(line):
    """
    获得字符串最后一个代码语义块
    :param line:
    :return:
    """
    if "return " in line:
        line = line.replace("return ", '')
    stack = []
    singleQuote = False
    doubleQoute = False
    for j in range(len(line)):
        i = len(line) - j - 1
        char = line[i]
        if char == "'":
            singleQuote = not singleQuote
        elif char == '"':
            doubleQoute = not doubleQoute
        if not singleQuote and not doubleQoute:
            if char == ")" or char == "]" or char == "}":
                stack.append(line[i])
            else:
                if char == "(" and (len(stack) == 0 or stack.pop() != ")"):
                    # print("Error")
                    return line[i + 1:]
                if char == "[" and (len(stack) == 0 or stack.pop() != "]"):
                    # print("Error")
                    return line[i + 1:]
                if char == "{" and (len(stack) == 0 or stack.pop() != "}"):
                    # print("Error")
                    return line[i + 1:]
                elif char == "," or line[i] == "=" or (char == "." and i - 1 >= 0 and line[i - 1] == "."):
                    if len(stack) == 0:
                        return line[i + 1:]

    if singleQuote or doubleQoute:
        print("Quote Error")
    if len(stack) is not 0:
        return False
    return line


def checkBlockComplete(line):
    """
    检查该行代码是否语义完整
    :param line:
    :return:
    """
    if not checkFirstBlockOfLine(line):
        return False
    else:
        tmp, _ = checkFirstBlockOfLine(line)
        return line == tmp


def RemoveCommentInLine(luaLineContent):
    Splits = luaLineContent.split("--")
    if len(Splits) >= 2:
        luaLineContent = luaLineContent.replace("--" + Splits[-1], "")
        if not checkBlockComplete(luaLineContent):
            luaLineContent += "--" + Splits[-1]
    return luaLineContent
    pass