本文共 4281 字,大约阅读时间需要 14 分钟。
给定一个表示代码片段的字符串,你需要实现一个验证器来解析这段代码,并返回它是否合法。合法的代码片段需要遵守以下的所有规则:
代码必须被合法的闭合标签包围。否则,代码是无效的。 闭合标签(不一定合法)要严格符合格式:<TAG_NAME>TAG_CONTENT</TAG_NAME>。其中,<TAG_NAME>是起始标签, </TAG_NAME>是结束标签。起始和结束标签中的 TAG_NAME 应当相同。当且仅当 TAG_NAME 和 TAG_CONTENT 都是合法的, 闭合标签才是合法的。 1.合法的 TAG_NAME 仅含有大写字母,长度在范围 [1,9] 之间。否则,该 TAG_NAME 是不合法的。 2.合法的 TAG_CONTENT 可以包含其他合法的闭合标签,cdata (请参考规则7)和任意字符(注意参考规则1)除了不匹配的<、 不匹配的起始和结束标签、不匹配的或带有不合法 TAG_NAME 的闭合标签。否则,TAG_CONTENT 是不合法的。 一个起始标签,如果没有具有相同 TAG_NAME 的结束标签与之匹配,是不合法的。反之亦然。不过,你也需要考虑标签嵌套的问题。 3.一个<,如果你找不到一个后续的>与之匹配,是不合法的。并且当你找到一个<或</时,所有直到下一个>的前的字符,都应当被解析为 TAG_NAME (不一定合法)。 4.cdata 有如下格式:<![CDATA[CDATA_CONTENT]]>。CDATA_CONTENT 的范围被定义成 <![CDATA[ 和后续的第一个 ]]>之间的字符。 CDATA_CONTENT 可以包含任意字符。cdata 的功能是阻止验证器解析CDATA_CONTENT,所以即使其中有一些字符可以被解析为标签( 无论合法还是不合法),也应该将它们视为常规字符。 合法代码的例子: 输入: "<DIV>This is the first line <![CDATA[<div>]]></DIV>" 输出: True 解释: 代码被包含在了闭合的标签内: <DIV> 和 </DIV> 。 TAG_NAME 是合法的,TAG_CONTENT 包含了一些字符和 cdata 。 即使 CDATA_CONTENT 含有不匹配的起始标签和不合法的 TAG_NAME,它应该被视为普通的文本,而不是标签。 所以 TAG_CONTENT 是合法的,因此代码是合法的。最终返回True。 输入: "<DIV>>> ![cdata[]] <![CDATA[<div>]>]]>]]>>]</DIV>" 输出: True 解释: 我们首先将代码分割为: start_tag|tag_content|end_tag 。 start_tag -> "<DIV>" end_tag -> "</DIV>" tag_content 也可被分割为: text1|cdata|text2 。 text1 -> ">> ![cdata[]] " cdata -> "<![CDATA[<div>]>]]>" ,其中 CDATA_CONTENT 为 "<div>]>" text2 -> "]]>>]" start_tag 不是 "<DIV>>>" 的原因参照规则 6 。 cdata 不是 "<![CDATA[<div>]>]]>]]>" 的原因参照规则 7 。 不合法代码的例子: 输入: "<A> <B> </A> </B>" 输出: False 解释: 不合法。如果 "<A>" 是闭合的,那么 "<B>" 一定是不匹配的,反之亦然。 输入: "<DIV> div tag is not closed <DIV>" 输出: False 输入: "<DIV> unmatched < </DIV>" 输出: False 输入: "<DIV> closed tags with invalid tag name <b>123</b> </DIV>" 输出: False 输入: "<DIV> unmatched tags with invalid tag name </1234567890> and <CDATA[[]]> </DIV>" 输出: False 输入: "<DIV> unmatched start tag <B> and unmatched end tag </C> </DIV>" 输出: False 注意: 为简明起见,你可以假设输入的代码(包括提到的任意字符)只包含数字, 字母, '<','>','/','!','[',']'和' '。
【最初思路】
1.把字符串分为三部分 <1>首标签 <2>body主体 <3>尾标签 首先判断首位标签是否合法 <1.大写字母><2.长度1-9><3.首尾仅差一个/><4.被<>所包含> 2.判断主体三部分 <1>text1 <2>cdata <3>text2 文本判断:不能有不匹配的<,不匹配的起始标签或结束标签,或者不合法的闭合标签 <2.1关于<没有>与之匹配,是不合法。并且一个<或</,所有直到下一个>的前的字符,都应当被解析为 TAG_NAME <2.2关于<![CDATA[body]]> body里的东西不用管 没有遇到<就是txt1 主体里面是否有标签嵌套只要不遇到<,就是txt1,判断是否合法 1.遇到<判断是否是cdata 若是cdata 2.不是寻找>并先判断首尾标签是否合法,合法递归判断该嵌套标签是否合法 3.判断txt2是否合法【最终思路】
1.body字符串不能遍历,复杂度太高 使用字符串的contains方法,delete方法和replace方法 2.解决cdata问题,while循环+delete 遇到cdata首尾标签一块删 遇到尾小于首,在内层加while循环中,循环删除,直至直到符合要求的首尾标签 跳出,若找不到符合要求的尾标签,尾标签删除完毕,return false 跳出条件: <1.字符串中不再包含首cdata 3.解决body剩余部分可能包含嵌套标签的问题 思路根cdata大致相同,区别:不能直接删除,而是用 { 代替 < ,用 } 代替 > 先用oldstring复制一份经过2过程的body字符串备用 <如果能找到索引比它大的>就是一对 如果索引比它小就进入内层循环,把>变成 } ,一直找,若找不到,就return false,找到了就把一对变换并记录下标,跳出 当集合里有大小为四时就递归调用judge函数,并清空集合 跳出条件 <1.字符串中不再包含< 跳出后如果集合有两个元素,return false 完成上述操作而没有提前返回false的返回truepublic class demo{ public static boolean judge(String tag) { int len1 = 0; String[] strings = new String[3]; for(int i=0;i') { len1 = i+1; break; } }else { return false; } } int len2 = 0; for(int i=tag.length()-1;i>=0;i--) { if(tag.charAt(tag.length()-1)=='>') { if(tag.charAt(i)=='<') { len2 = i; break; } }else { return false; } } strings[1] = tag.substring(len2,tag.length()); strings[2] = tag.substring(len1,len2); strings[0] = tag.substring(0,len1); /*System.out.println(strings[1]); System.out.println(strings[2]); System.out.println(strings[0]);*/ if(strings[1].startsWith(" ='A'&&s1<='Z')&&(s2>='A'&&s2<='Z')))) { return false; } strings1Index++; } }else { return false; } int index1 = 0,index2 = 0; while(true) { if(strings[2].contains("")) { index2 = strings[2].indexOf("]]>"); } if(index1 ")) { index2 = strings[2].indexOf("]]>"); }else { return false; } if(index1 list = new ArrayList<>(); while(true) { if(strings[2].contains("<")) { t1 = strings[2].indexOf("<"); }else { break; } if(strings[2].contains(">")) { t2 = strings[2].indexOf('>'); } if(t1 ")) { t2 = strings[2].indexOf(">"); } if(strings[2].contains("<")&&!(strings[2].contains(">"))) { return false; } if(t1
转载地址:http://biazi.baihongyu.com/