05 代码片格式化
2015-10-22 21:25
381 查看
前言
这是一个之前没事的时候的一个想法, 想想他们博客的代码的显示格式化的问题, 然后 在网上找了一下资源, 恰好有一个网友也做了, 然后就下载了, 参考了一下, 但是原来作者是使用正则替换各个关键字的显示, 注释等等 […我有点看不懂], 所以后来自己想了一下, 不过当你第一映像想到的东西几乎是最简单[最容易想到的]的实现方法, 所以 这里的实现也算是一个普通的算法吧
主要知识点 : 按照给定的多个分隔符进行分词, 以及拼接html, 以及特殊字符的替换 [空格, <, > 等等]
需要输入的数据如下, keys [关键字 -> 样式class的映射], seps [分隔符, 用于分词], singleLineAnno [单行注释], multiLineAnno [多上注释 [开始注释 -> 结束注释的映射] ]
请注意 : singleLineAnno 以及multiLineAnno中的符号必需出现在seps中, 否则 无法执行注释的判断逻辑
如果你需要添加一种语言的”渲染”
1. 现在formatCodeSegment.html页面添加 < select id=”lang” > 标签下面添加一个类似于< option value =”java”>Java< /option>的标签
2. 在formatCodeSegment.js脚本中添加添加上面的四个配置, 然后更新一下initKeysAndSeps, 添加入你添加的样式对于核心业务逻辑的”keys, seps, singleLineAnno, multiLineAnno”的配置即可
主要的思路如下 : 对于一行数据, 将其按照seps进行分词, 首先判断当前分隔符
1) 如果当前multiLineAnnoEle为空, 即当前行不在多行注释的范围内
1 如果当前分割符为”“” 或者”’”, 即双引号 或者单引号, 则获取下一个匹配的引号的位置, 然后将引号以及之间的内容添加为引号的样式块[< span class=’quote /singleQuote’ >]
2 如果当前分割符为单行注释符号[通常有 “//”, “#”, “;”等等], 各个语言更具自己的情况进行配置singleLineAnno 将当前行当前分隔符之后的数据作为注释快添加为注释的样式块[< span class=’conmment’ >]
3 如果当前当前分割符为多行注释符号[通常有 “/, /”, “{, }” 等等]各个语言更具自己的情况进行配置multiLineAnno,
尝试在当前行获取注释的结束符号 如果存在, 则将注释符号之间的部分添加为注释块[< span class=’conmment’ >]
如果当前行不存在注释结束符, 则设置multiLineAnnoEle为开始的”多行注释的符号”, 然后递归当前方法进入if(multiLineAnnoEle != null)判定, 执行解决多行注释的逻辑, 将结果添加为注释快[< span class=’conmment’ >]
4 剩余的就只有普通的单词, 以及关键字单词了, 分别处理 如果是关键字单词, 添加该单词对应的关键字的样式[keys 中配置]
2) 如果当前multiLineAnnoEle不为空, 即当前行在多行注释的范围内
1. 判定当前行是否有multiLineAnnoEle对应的注释结束符
如果存在 则将到注释结束符之前的内容均添加为注释块样式, 并设置multiLineAnnoEle为null, 解析注释结束符之后的数据 [之后进入的是”multiLineAnnoEle==null”的分支]
否则 将当前行添加为注释快样式
分词的图示 :
核心代码
1 formatCodeSegment.html : 前台显示代码
2 getCodeKeyAndSeps.js : 生成控制着管理”keys, seps, singleLineAnno, multiLineAnno” 配置的逻辑
4 formatCodeSegment.js : js实现的StringBuilder
3 formatCodeSegment.js : 控制着核心”渲染”逻辑, 根据每一行数据, 进行样式化数据
效果截图 :
因为在浏览器中点击’ 或者”, 就导致了浏览器当前页面不响应了, 所以 这里演示以”`”代替了”“”
敲一段代码 :
语言模式的切换 :
参考 : http://download.csdn.net/detail/cawarey/4295065
下载链接 [包含图片, 源码] :
http://download.csdn.net/detail/u011039332/9204535
注 : 因为作者的水平有限,必然可能出现一些bug, 所以请大家指出!
这是一个之前没事的时候的一个想法, 想想他们博客的代码的显示格式化的问题, 然后 在网上找了一下资源, 恰好有一个网友也做了, 然后就下载了, 参考了一下, 但是原来作者是使用正则替换各个关键字的显示, 注释等等 […我有点看不懂], 所以后来自己想了一下, 不过当你第一映像想到的东西几乎是最简单[最容易想到的]的实现方法, 所以 这里的实现也算是一个普通的算法吧
主要知识点 : 按照给定的多个分隔符进行分词, 以及拼接html, 以及特殊字符的替换 [空格, <, > 等等]
需要输入的数据如下, keys [关键字 -> 样式class的映射], seps [分隔符, 用于分词], singleLineAnno [单行注释], multiLineAnno [多上注释 [开始注释 -> 结束注释的映射] ]
请注意 : singleLineAnno 以及multiLineAnno中的符号必需出现在seps中, 否则 无法执行注释的判断逻辑
如果你需要添加一种语言的”渲染”
1. 现在formatCodeSegment.html页面添加 < select id=”lang” > 标签下面添加一个类似于< option value =”java”>Java< /option>的标签
2. 在formatCodeSegment.js脚本中添加添加上面的四个配置, 然后更新一下initKeysAndSeps, 添加入你添加的样式对于核心业务逻辑的”keys, seps, singleLineAnno, multiLineAnno”的配置即可
主要的思路如下 : 对于一行数据, 将其按照seps进行分词, 首先判断当前分隔符
1) 如果当前multiLineAnnoEle为空, 即当前行不在多行注释的范围内
1 如果当前分割符为”“” 或者”’”, 即双引号 或者单引号, 则获取下一个匹配的引号的位置, 然后将引号以及之间的内容添加为引号的样式块[< span class=’quote /singleQuote’ >]
2 如果当前分割符为单行注释符号[通常有 “//”, “#”, “;”等等], 各个语言更具自己的情况进行配置singleLineAnno 将当前行当前分隔符之后的数据作为注释快添加为注释的样式块[< span class=’conmment’ >]
3 如果当前当前分割符为多行注释符号[通常有 “/, /”, “{, }” 等等]各个语言更具自己的情况进行配置multiLineAnno,
尝试在当前行获取注释的结束符号 如果存在, 则将注释符号之间的部分添加为注释块[< span class=’conmment’ >]
如果当前行不存在注释结束符, 则设置multiLineAnnoEle为开始的”多行注释的符号”, 然后递归当前方法进入if(multiLineAnnoEle != null)判定, 执行解决多行注释的逻辑, 将结果添加为注释快[< span class=’conmment’ >]
4 剩余的就只有普通的单词, 以及关键字单词了, 分别处理 如果是关键字单词, 添加该单词对应的关键字的样式[keys 中配置]
2) 如果当前multiLineAnnoEle不为空, 即当前行在多行注释的范围内
1. 判定当前行是否有multiLineAnnoEle对应的注释结束符
如果存在 则将到注释结束符之前的内容均添加为注释块样式, 并设置multiLineAnnoEle为null, 解析注释结束符之后的数据 [之后进入的是”multiLineAnnoEle==null”的分支]
否则 将当前行添加为注释快样式
分词的图示 :
核心代码
1 formatCodeSegment.html : 前台显示代码
<body> <textarea id="code" class='inputTextArea' oninput="format()" ></textarea> <select id="lang" onchange="format()" > <option value ="java">Java</option> <option value ="c++">C++</option> <option value="c">C</option> <option value="scala">Scala</option> </select> <br/><br/> 预览效果: <button onclick="copyToClipBoard()">一键复制</button> <span id="result"></span> </body>
2 getCodeKeyAndSeps.js : 生成控制着管理”keys, seps, singleLineAnno, multiLineAnno” 配置的逻辑
// 初始化逻辑需要使用的keys, seps [根据语言不通, 而不通] // 如果想要添加其他语言, 请接着if ... else if 配置 function initKeysAndSeps(lang) { if(equalsIgnoreCase("java", lang) ) { keys = javaKeys seps = javaSeps singleLineAnno = javaSingleLineAnno multiLineAnno = javaMultiLineAnno } else if(equalsIgnoreCase("c++", lang) ) { keys = cppKeys seps = cppSeps singleLineAnno = cppSingleLineAnno multiLineAnno = cppMultiLineAnno } else if(equalsIgnoreCase("c", lang) ) { keys = cKeys seps = cSeps singleLineAnno = cSingleLineAnno multiLineAnno = cMultiLineAnno } else if(equalsIgnoreCase("scala", lang) ) { keys = scalaKeys seps = scalaSeps singleLineAnno = scalaSingleLineAnno multiLineAnno = scalaMultiLineAnno } }
4 formatCodeSegment.js : js实现的StringBuilder
// js实现StringBuilder function StringBuilder() { this._stringArray = new Array(); } StringBuilder.prototype.append = function(str){ this._stringArray.push(str); } StringBuilder.prototype.toString = function(sep){ return this._stringArray.join(sep); }
3 formatCodeSegment.js : 控制着核心”渲染”逻辑, 根据每一行数据, 进行样式化数据
// 格式化给定的输入 // 遍历每一行, 进行格式化 // 并且更新li颜色间隔显示, 以及鼠标高亮显示 function format() { var codeRows = document.getElementById("code").value.split("\n") var result = document.getElementById("result") initKeysAndSeps(document.getElementById("lang").value) var resultContent = new StringBuilder() resultContent.append(olCodeStart) for(i in codeRows) { resultContent.append(liCodeStart) var row = formatOneRow(codeRows[i], copyOfArray(seps) ) resultContent.append(row) resultContent.append(liCodeEnd) } resultContent.append(olCodeEnd) // log(resultContent.toString("") ) result.innerHTML = resultContent.toString("") liColor() } var multiLineAnnoEle = null // 格式化一行代码 // 分词, 格式化数据 function formatOneRow(row, seps) { if(multiLineAnnoEle != null) { var formatted = new StringBuilder() var endComment = multiLineAnno[multiLineAnnoEle] var endCommentIdx = row.indexOf(endComment) if(endCommentIdx >= 0) { appendComment(formatted, row.substring(0, endCommentIdx + endComment.length) ) formatted.append(formatOneRow(row.substr(endCommentIdx + endComment.length), seps) ) multiLineAnnoEle = null } else { appendComment(formatted, row) } return formatted.toString(""); } else { var formatted = new StringBuilder() var copyOfSeps = copyOfArray(seps) var sepsMap = {} for(i in seps) { sepsMap[seps[i]] = -1 } updateSeps(sepsMap, seps, row, 0) // lastMinIdx 控制着是否需要更新上一个轮询的最小的分隔符 var lastMinIdx = -1 var lastIdx = 0 while(getLength(sepsMap) > 0) { if(lastMinIdx != -1) { sepsMap[seps[lastMinIdx]] = row.indexOf(seps[lastMinIdx], lastIdx) if(sepsMap[seps[lastMinIdx]] < 0) { delete sepsMap[seps[lastMinIdx]] delete seps[lastMinIdx] } } if(getLength(sepsMap) == 0) { break } lastMinIdx = getMinIdx(sepsMap, seps) // log(lastIdx + " -> " + sepsMap[seps[lastMinIdx]]) var word = row.substring(lastIdx, sepsMap[seps[lastMinIdx]]) lastIdx = sepsMap[seps[lastMinIdx]] + seps[lastMinIdx].length // 至此 word表示当前分割符的前一个字符串, seps[lastMinIdx]表示当前分隔符 // 判断各个分隔符特有的样式 [比如 这里的单引号, 双引号] if(seps[lastMinIdx] == "\"") { appendWord(formatted, word) var nextQuote = row.indexOf(seps[lastMinIdx], lastIdx) + seps[lastMinIdx].length appendQuote(formatted, row.substring(sepsMap[seps[lastMinIdx]], nextQuote) ) updateSeps(sepsMap, seps, row, nextQuote) lastIdx = nextQuote lastMinIdx = -1 } else if (seps[lastMinIdx] == "'") { appendWord(formatted, word) var nextQuote = row.indexOf(seps[lastMinIdx], lastIdx) + seps[lastMinIdx].length appendSingleQuote(formatted, row.substring(sepsMap[seps[lastMinIdx]], nextQuote) ) updateSeps(sepsMap, seps, row, nextQuote) lastIdx = nextQuote lastMinIdx = -1 } else if(containsEle(singleLineAnno, seps[lastMinIdx]) ) { appendWord(formatted, word) appendComment(formatted, row.substr(sepsMap[seps[lastMinIdx]]) ) return formatted.toString("") } else if(multiLineAnno[seps[lastMinIdx]] != null) { multiLineAnnoEle = seps[lastMinIdx]; appendComment(formatted, word) formatted.append(formatOneRow(row.substr(seps[lastMinIdx]) )) return formatted.toString("") } else { appendWord(formatted, word) appendSep(formatted, seps[lastMinIdx]) } } // 处理最后一个元素 var word = row.substr(lastIdx) appendWord(formatted, word) return formatted.toString("") } } // 更新li行的颜色 function liColor() { tabNode = document.getElementById("result").getElementsByTagName("ol")[0]; trs = tabNode.getElementsByTagName("li"); for(var i=0; i<trs.length; i++) { if(i&1 == 1){ trs[i].className += " oddLi"; } else { trs[i].className += " evenLi"; } trs[i].onmouseover = function() { this.className += " overLi"; } // 不能使用"-=", 因为"-" 并不为字符串连接符 trs[i].onmouseout = function() { this.className = this.className.substring(0, this.className.indexOf("overLi") ) } } } // ---------知识点---------- // 判断给定的key是否在字典中存在 // console.log(keys["sdf"] == null) // 字符串化给定的json对象 // var sepsMap = {"sdf":"sdf"} // console.log(JSON.stringify(sepsMap) ) // 字符串化给定的json对象 // var sepsMap = JSON.parse('{"sdf":"sdf"}'') // console.log(sepsMap ) // 删除给定的元素 // delete sepsMap["ele"] // for..in 如果集合是数组, 则迭代的是索引, 否则 集合中的元素 // ---------!知识点----------
效果截图 :
因为在浏览器中点击’ 或者”, 就导致了浏览器当前页面不响应了, 所以 这里演示以”`”代替了”“”
敲一段代码 :
语言模式的切换 :
参考 : http://download.csdn.net/detail/cawarey/4295065
下载链接 [包含图片, 源码] :
http://download.csdn.net/detail/u011039332/9204535
注 : 因为作者的水平有限,必然可能出现一些bug, 所以请大家指出!
相关文章推荐
- android 代码实现控件之间的间距
- [Android]在代码里运行另一个程序的方法
- 肯特·贝克:改变人生的代码整理魔法
- 新注册
- 网页恶意代码的预防
- 高手写的Tracer-Flash代码调试类代码下载
- Flex中对表格某列的值进行数字格式化并求百分比添加%
- CSS代码缩写技巧
- 非主流Q-zOne代码代码搜集第1/2页
- 四大漏洞入侵博客
- CreateWeb.vbs 代码
- Lua中编译执行代码相关的函数详解
- asp格式化日期时间格式的代码
- 更有效率的css代码编写第1/3页
- 在Ubuntu系统上安装Ghost博客平台的教程
- 代码中到底应不应当写注释?
- SQL语言查询基础:连接查询 联合查询 代码
- 论坛头像随机变换代码
- .NET 常用功能和代码小结
- C#实现压缩HTML代码的方法