既然我们已经找到了歌词的头,那么只要我们找到歌词的结尾并选取在这之间的内容差不多就算完成了。findEndTag() 函数用来查找歌词的结尾。
function findEndTag() { var lastIndex = htmlData.lastIndexOf("]"); if (htmlData.slice(lastIndex-3, lastIndex-2) == "." && htmlData.slice(lastIndex-6, lastIndex-5) == ":") { var tmpBR = htmlData.slice(lastIndex); htmlData = htmlData.slice(0, lastIndex+tmpBR.indexOf("<br")+3); htmlData = htmlData.slice(0, htmlData.indexOf("</")); } else { htmlData = htmlData.slice(0, lastIndex); if (loopStart == undefined) { loopCount = 1; } else { delete loopStart; } if (loopCount<254) { loopStart = true; loopCount++; findEndTag(); } } }
LRC歌词是有特征可以区别的。看看LRC文件,它每一行都包含了像"[00:30.11]"这样的时间标记,我们的目标就是找到它。首先我们查找 "]" (不能查找 "[00:30.11]" ,里面的时间是不确定的,flash 也不支持正则的方式)
var lastIndex = htmlData.lastIndexOf("]") 使用lastIndexOf()从后面向前查找的方式找到最后一个 "]" 字符。这里我们用到了一个 var 声明一个局部变量。如果你在函数过程中要使用一个临时性的东西,都最好先用var声明一下,它将在函数运行完后自动销毁,以便更节省内存(另外一个好处就是可以帮你防止和外面的名字冲突而引起不必要的麻烦)
但光有这些还不够,下一步就是要验证我们找到是不是像"[00:30.11]"这样的字符。要完成验证的另外一个原因就是可能网页中(特别是论坛贴子中)其它地方也可能出现"]"这样的字符。它们可能包含一大堆像"[3]:我想找...[4]:喜欢这歌,顶下"、"第[1]页"这样的包含"]"字符内容(甚至是像[ MP=480,360,false]http://music.f4666.com/music/turanziwo.mp3[/MP]"这样的论坛发贴的代码)。可以参考一下这个网页或其它论坛: www.zjnetcafe.com/html/7/60586.htm
if (htmlData.slice(lastIndex-3, lastIndex-2) == "." && htmlData.slice(lastIndex-6, lastIndex-5) == ":") 对它进行验证,在这里我只验证两个字符:在它前面3个字符的"." 和 在它前面6个字符的":"。你可以加上验证在它前面9个字符的"["来加强验证。代码是:
if (htmlData.slice(lastIndex-3, lastIndex-2) == "." && htmlData.slice(lastIndex-6, lastIndex-5) == ":" && htmlData.slice(lastIndex-9, lastIndex-8) == "[")
如果验证失败(也就是说它不是我们想找的像"[00:30.11]"这样的标签),我们将再向前搜索直到找到这个标签为止,跳到else部份: else { htmlData = htmlData.slice(0, lastIndex); ...... findEndTag(); } } htmlData = htmlData.slice(0, lastIndex) 截取在找到的"]"这个字符之前的内容用作以后的处理,findEndTag() 使它继续重复上面查找验证的工作。 注意,findEndTag()运行了它自已身,我们的整个查找验证的函数实际上是一个自循环(自已在函数内部调用自已)。 flash中一个函数递归256次的限制。也就是一个函数不能重复执行256次。超过256次 flash 就将终止它并可能停止执行所有的ActionScript(接近于程序崩溃了) 这里我们自行加了一个计数器判断将执行次数限制在256次以内以免到时flashPlayer终止它让你的程序崩溃。 if (loopStart == undefined) { loopCount = 1; } else { delete loopStart; } if (loopCount<254) { loopStart = true; loopCount++; 这里用了一个一个相互排斥的锁定的方法以使函数明白自已是不是第一次执行。如果是,则重新开始计数。如果不是,则将计数器累加,并将次数限制在规定次数以内。
自循环函数是比较危险的,如果不是必要,请尽量少使用它。(或者用两个AB相同的函数交叉调用代替,但也请注意别让函数陷在死循环里跳不出来,极度危险。更好的解决方案是将函数的执行放在onEnterFrame事件中,但可能会牺牲点执行速度,写法如下:) function findEndTag() { this.onEnterFrame=function(){ var lastIndex = htmlData.lastIndexOf("]"); if (htmlData.slice(lastIndex-3, lastIndex-2) == "." && htmlData.slice(lastIndex-6, lastIndex-5) == ":") { var tmpBR = htmlData.slice(lastIndex); htmlData = htmlData.slice(0, lastIndex+tmpBR.indexOf("<br")+3); htmlData = htmlData.slice(0, htmlData.indexOf("</")); delete this.onEnterFrame; doFunction(); } else { htmlData = htmlData.slice(0, lastIndex); } } } 我们回到验证成功后的部份: var tmpBR = htmlData.slice(lastIndex); htmlData = htmlData.slice(0, lastIndex+tmpBR.indexOf("<br")+3); htmlData = htmlData.slice(0, htmlData.indexOf("</")); 我们只过滤掉我们不想要的部份,注意,不是从"]"这个字符串的位置过滤,这样你将丢掉最后一行歌词的内容。我们查找最靠近这一行歌词的源代码标签(这里我们开始要用到源代码来识别了)"<br"方法是将"]"之后的内容截成一个临时的字符串并查找它的第一个位置,然后将它和前面的"]"位置累加得到最终的这个截取点。 因为有些歌词的旁边并没有"<br" 标签,它可能放在一个容器中(如文本框或者最后没有"<br"结尾的表格),所我们加上这一句:htmlData = htmlData.slice(0, htmlData.indexOf("</")) 用高级的查找方式(加个起始位置参数)你也可以将上面的代码直接写成这样: htmlData = htmlData.slice(0, htmlData.indexOf("<br",lastIndex)+3); htmlData = htmlData.slice(0, htmlData.indexOf("</"));
最后我们回到这里: htmlData = htmlData.split("<br>").join("\n"); htmlData = htmlData.split("<br />").join("\n"); lrcData = htmlData.split(String.fromCharCode(10)).join("");
看看最后我们得到的LRC歌词内容,它大致是下面的样子: ...... [ti:突然的自我]<br> [ar:黄小琥]<br> [al:]<br> [by:wolfpey]<br> [offset:500]<br> [00:02.67]《突然的自我》<br> [00:10.12]作词:伍佰 徐克<br> [00:11.67]作曲/编曲:伍佰<br> [00:12.30]演唱:黄小琥<br> ...... 最后我们将所有<br>标签去除并替换成换行符 "\n"(LRC分行的写法)。 (注:split().join()用来替换字符串,请参见wersling的站点:http://www.wersling.com/blog/ )
考虑到html和xhtml的兼容性,所以这里用了两次同样的方法。第一次对html常用的"<br>"标签进行替换,第二次对xhtml的"<br />"标签进行替换。 如果再考虑到大小写"<BR>"的问题,应该再写成这样: htmlData = htmlData.split("<br>").join("\n"); htmlData = htmlData.split("<BR>").join("\n"); htmlData = htmlData.split("<Br>").join("\n"); htmlData = htmlData.split("<bR>").join("\n"); htmlData = htmlData.split("<br />").join("\n"); htmlData = htmlData.split("<BR />").join("\n"); htmlData = htmlData.split("<Br />").join("\n"); htmlData = htmlData.split("<bR />").join("\n"); 也可以用先转换大小写的方式(但请注意记得还原原来LRC内容的大小写),幸好这里还不算太长(只有br两个字母)
最后,去掉多余的换行符。(String.fromCharCode(10) 等同于 "\n" );
(考虑对特别内容的兼容性,最后一行代码其实还是有些问题的,一些站点可能并没有"<br>"标签而直接用换行符替代,这样最后一行代码会引发问题。) 如果再加上某些站点可能使用回车符换行的方式,应该替换成这样(共有4种组合方式): 回车+回车;回车+换行;换行+换行;换行+回车; 或者设计一个循环检查代码(针对三个以上连续回车换行的情况,这种情况极少)
源文件: http://www.blueidea.com/articleimg/2006/01/3161/lrcSearch.rar
出处:蓝色理想
责任编辑:蓝色月光
上一页 本地直接从百度获取LRC歌词 三 下一页 实用性的东西
◎进入论坛Flash专栏版块参加讨论
|