当前位置: 首页 > news >正文

编写个人网站如何建购物网站

编写个人网站,如何建购物网站,便宜做网站怎么样,网站建设公司年终总结话说我要为技术博客写一个小程序版#xff0c;我的博客解决方案是 hexo github-page#xff0c;格式当然是技术控们喜欢的 markdown 了 。但小程序使用的却是独有的模版语言 WXML。我总不能把之前的文章手动转换成小程序的 wxml 格式吧#xff0c;而网上也没完善的转换库我的博客解决方案是 hexo github-page格式当然是技术控们喜欢的 markdown 了 。但小程序使用的却是独有的模版语言 WXML。我总不能把之前的文章手动转换成小程序的 wxml 格式吧而网上也没完善的转换库还是自己写个解析器吧。 解析器最核心的部分就是字符串模式匹配既然涉及到字符串匹配那么就离不开正则表达式。幸好正则表达式是我的优势之一。 正则表达式 JavaScript中的正则表达式 解析器涉及到的 JavaScript 正则表达式知识 RegExp 构造函数属性其中lastMatchrightContent在字符串截取时非常有用 长属性名短属性名替换标志说明input$_最近一次要匹配的字符串。Opera未实现此属性lastMatch$$最近一次的匹配项。Opera未实现此属性lastParen$最近一次匹配的捕获组。Opera未实现此属性leftContextinput字符串中lastMatch之前的文本rightContext$$Input字符串中lastMatch之后的文本multiline$*布尔值表示是否所有表达式都使用多行模式。IE和Opera未实现此属性$n$n分组$$转义$ test 方法 和 RegExp 构造函数 test 方法调用后上面的属性就会出现在 RegExp 中不推荐使用短属性名因为会造成代码可读性的问题下面就是样例 var text this has been a short summer; var pattern /(.)hort/g;if (pattern.test(text)){alert(RegExp.input); // this has been a short summeralert(RegExp.leftContext); // this has been aalert(RegExp.rightContext); // summeralert(RegExp.lastMatch); // shortalert(RegExp.lastParen); // salert(RegExp.multiline); // false }//长属性名都可以用相应的短属性名来代替。不过由于这些短属性名大都不是有效的ECMAScript标识符因此必须通过方括号语法来访问它们 if (pattern.test(text)){alert(RegExp.$_);alert(RegExp[$]);alert(RegExp[$]);alert(RegExp[$]);alert(RegExp[$]);alert(RegExp[$*]); } 复制代码 replace 方法 一般使用的是没有回调函数的简单版本而回调函数版本则是个大杀器及其强大 //简单替换, replace默认只进行一次替换, 如设定全局模式, 将会对符合条件的子字符串进行多次替换最后返回经过多次替换的结果字符串. var regex /(\d{4})-(\d{2})-(\d{2})/; 2011-11-11.replace(regex, $2/$3/$1);//replace 使用回调函数自定义替换必须启用全局模式g因为要不断向前匹配直到匹配完整个字符串 //match为当前匹配到的字符串index为当前匹配结果在字符串中的位置sourceStr表示原字符串 //如果有分组则中间多了匹配到的分组内容match,group1(分组1)...groupN(分组n),index,sourceStr one two three.replace(/\bt[a-zA-Z]\b/g, function (match,index,str) { //将非开头的单词大写console.log(match,index,str);return match.toUpperCase(); }); 复制代码 match 方法 全局模式和非全局模式有显著的区别全局模式和 exec 方法类似。 // 如果参数中传入的是子字符串或是没有进行全局匹配的正则表达式那么match()方法会从开始位置执行一次匹配如果没有匹配到结果则返回null.否则则会返回一个数组,该数组的第0个元素存放的是匹配文本返回的数组还含有两个对象属性index和input分别表示匹配文本的起始字符索引和原字符串还有分组属性 var str 1a2b3c4d5e; console.log(str.match(/b/)); //返回[b, index: 3, input: 1a2b3c4d5e]//如果参数传入的是具有全局匹配的正则表达式那么match()从开始位置进行多次匹配直到最后.如果没有匹配到结果则返回null.否则则会返回一个数组数组中存放所有符合要求的子字符串但没有index和input属性,也没有分组属性 var str 1a2b3c4d5e; str.match(/h/g); //返回null str.match(/\d/g); //返回[1, 2, 3, 4, 5]var pattern /\d{4}-\d{2}-\d{2}/g; var str 2010-11-10 2012-12-12; var matchArray str.match(pattern); for(vari 0; i matchArray.length; i) {console.log(matchArray[i]); } 复制代码 exec 方法 与全局模式下的 match 类似但 exec 更强大因为返回结果包含各种匹配信息而match全局模式是不包含具体匹配信息的。 //逐步提取,捕获分组匹配文本,必须使用全局模式g, 成功则返回数组(包含匹配的分组信息), 否则为null //Regex每次匹配成功后,会把匹配结束位置更新到lastIndex,下次从lastIndex开始匹配 //如果不指定全局模式,使用while循环,会造成无穷循环 var pattern /(\d{4})-(\d{2})-(\d{2})/g; var str2 2011-11-11 2013-13-13 ; while ((matchArray pattern.exec(str2)) ! null) {console.log( date: matchArray[0]start at: matchArray.index ends at: pattern.lastIndex);console.log( ,year: matchArray[1]);console.log( ,month: matchArray[2]);console.log( ,day: matchArray[3]); } 复制代码 searchsplit 这两个比较简单的方法则不再介绍 正则表达式高级概念 正常情况下正则是从左向右进行单字符匹配每匹配到一个字符, 就后移位置, 直到最终消耗完整个字符串 这就是正则表达式的字符串匹配过程也就是它会匹配字符占用字符。相关的基本概念不再讲解这里要讲的和字符匹配不同的概念 - 断言。 断言 正则中大多数结构都是匹配字符而断言则不同它不匹配字符不占用字符而只在某个位置判断左/右侧的文本是否符合要求。这类匹配位置的元素可以称为 锚点主要分为三类单词边界开始结束位置环视。 单词边界 \b 是这样的位置一边是单词字符一边不是单词字符如下字符串样例所示 \brow\b //row \brow //row rowdy row\b //row tomorow 复制代码^ 行开头多行模式下亦匹配每个换行符后的位置即行首 $ 行结束多行模式下亦匹配每个换行符前的位置即行尾 //js 中的 $ 只能匹配字符串的结束位置不会匹配末尾换行符之前的换行符。但开启多行模式(m)后^ 和 $ 则可以匹配中间的换行符。 如下例子可验证// 默认全局模式下^ 和 $ 直接匹配到了文本最开头和末尾忽略了中间的换行符 hello\nword.replace(/^|$/g,p) phello wordp// 多行模式下同时能匹配到结束符中间的换行符 hello\nword\nhi.replace(/^|$/mg,p) phellop pwordp phip 复制代码 环视 环视是断言中最强的存在同样不占用字符也不提取任何字符只匹配文本中的特定位置与\b, ^ $ 边界符号相似但环视更加强大因为它可以指定位置和在指定位置处添加向前或向后验证的条件。 而环视主要体现在它的不占位不消耗匹配字符, 因此又被称为零宽断言。所谓不占宽度可以这样理解 环视的匹配结果不纳入数据结果 环视它匹配过的地方下次还能用它继续匹配。 环视包括顺序环视和逆序环视javascript 在 ES 2018 才开始支持逆序环视 (?) 顺序肯定环视 匹配右边(?!) 顺序否定环视(?) 逆序肯定环视 匹配左边(?!) 逆序否定环视来看一下具体的样例 // 获取.exe后缀的文件名不使用分组捕获能使捕获结果不包含.exe后缀充分利用了环视匹配结果同时不占位的特性 asd.exe.match(/.(?\.exe)/)[asd, index: 0, input: asd.exe, groups: undefined]// 变种否定顺序环视排除特定标签p/a/img匹配html标签 /?(?!p|a|img)([^ /])[^]*/? //常规逆序环视同样利用了环视匹配不占位的特性 /(?\$)\d/.exec(Benjamin Franklin is on the $100 bill) // [100,index: 29,...] /(?!\$)\d/.exec(it’s is worth about €90) // [90, index: 21,...] // 利用环视占位但不匹配的特性 12345678.replace(/\B(?(\d{3})$)/g , ,) 12,345,678 //分割数字 复制代码解析器的编写 正则表达式相关写得有点多但磨刀不误砍柴工开始进入主题 markdown格式 hexo 生成的 markdwon 文件格式如下解析器就是要把它解析成json格式的输出结果供小程序输出 wxml --- title: Haskell学习-functor date: 2018-08-15 21:27:15 tags: [haskell] categories: 技术 banner: https://upload-images.jianshu.io/upload_images/127924-be9013350ffc4b88.jpg --- !-- 原文地址[Haskell学习-functor](https://edwardzhong.github.io/2018/08/15/haskellc/) -- ## 什么是Functor **functor** 就是可以执行map操作的对象functor就像是附加了语义的表达式可以用盒子进行比喻。**functor** 的定义可以这样理解给出a映射到b的函数和装了a的盒子结果会返回装了b的盒子。**fmap** 可以看作是一个接受一个function 和一个 **functor** 的函数它把function 应用到 **functor** 的每一个元素映射。haskell -- Functor的定义 class Functor f wherefmap :: (a - b) - f a - f b!-- more -- 复制代码入口 使用node进行文件操作然后调用解析器生成json文件 const { readdirSync, readFileSync, writeFile } require(fs); const path require(path); const parse require(./parse);const files readdirSync(path.join(__dirname, posts)); for (let p of files) {let md readFileSync(path.join(__dirname, posts, p));const objs parse(md);writeFile(path.join(__dirname, json, p.replace(.md,.json)), JSON.stringify(objs), function( err ){err console.log(err);}); } 复制代码来看一下解析器入口部分主要分为summary 部分code代码部分markdown文本部分。将文本内容的注释和空格过滤掉但是代码部分的注释要保留。 module.exports function analyze(str) {let ret { summary: {}, lines: [] };while (str) {// 空格if (/^([\s\t\r\n])/.test(str)) {str RegExp.rightContext;}// summary 内容块if (/^(\-{3})[\r\n]?([\s\S]?)\1[\r\n]?/.test(str)) {str RegExp.rightContext;ret.summary summaryParse(RegExp.$2);ret.num new Date(ret.summary.date).getTime();}// codeif (/^{3}(\w)?([\s\S]?){3}/.test(str)) {const codeStr RegExp.$2 || RegExp.$1;const fn (RegExp.$2 codeParse[RegExp.$1]) ? codeParse[RegExp.$1] : codeParse.javascript;str RegExp.rightContext;ret.lines.push({ type: code, child: fn(codeStr) });}// 注释行if (/^!--[\s\S]*?--/.test(str)) {str RegExp.rightContext;}// 提取每行字符串, 利用 . 不匹配换行符的特性if (/^(.)[\r\n]?/.test(str)) {str RegExp.rightContext;ret.lines.push(textParse(RegExp.$1));}}return ret; }; 复制代码文本内容提取 summary 内容块的提取比较简单不讲叙。还是看 markdown 文本内容的解析吧。这里匹配 markdown 常用类型比如列表标题h链接a图片img等。而返回结果的数据结构就是一个列表列表里面可以嵌套子列表。但基本就是正则表达式提取内容最终消耗完字符行。 function textParse(s) {const trans /^\\(\S)/; //转义字符const italy /^(\*)(.?)\1/; //倾斜const bold /^(\*{2})(.?)\1/; //加粗const italyBold /^(\*{3})(.?)\1/; //倾斜和加粗const headLine /^(\#{1,6})\s/; //h1-6const unsortList /^([*\-])\s/; //无序列表const sortList /^(\d)\.\s/; //有序列表const link /^\*?\[(.)\]\(([^()])\)\*?/; //链接const img /^(?:!\[([^\]])\]\(([^)])\)|img(\s)src([^]))/; //图片const text /^[^\\\s*]/; //普通文本if (headLine.test(s)) return { type: h RegExp.$1.length, text: RegExp.rightContext };if (sortList.test(s)) return { type: sl, num: RegExp.$1, child: lineParse(RegExp.rightContext) };if (unsortList.test(s)) return { type: ul, num: RegExp.$1, child: lineParse(RegExp.rightContext) };if (img.test(s)) return { type: img, src: RegExp.$2||RegExp.$4, alt: RegExp.$1||RegExp.$3 };if (link.test(s)) return { type: link, href: RegExp.$2, text: RegExp.$1 };return { type: text, child: lineParse(s) };function lineParse(line) {let ws [];while (line) {if (/^[\s]/.test(line)) {ws.push({ type: text, text: nbsp; });line RegExp.rightContext;}if (trans.test(line)) {ws.push({ type: text, text: RegExp.$1 });line RegExp.rightContext;}if (sortList.test(line)) {return { child: lineParse(RegExp.rightContext) };}if (unsortList.test(line)) {return { child: lineParse(RegExp.rightContext) };}if (link.test(line)) {ws.push({ type: link, href: RegExp.$2, text: RegExp.$1 });line RegExp.rightContext;}if (italyBold.test(line)) {ws.push({ type: italybold, text: RegExp.$2 });line RegExp.rightContext;}if (bold.test(line)) {ws.push({ type: bold, text: RegExp.$2 });line RegExp.rightContext;}if (italy.test(line)) {ws.push({ type: italy, text: RegExp.$2 });line RegExp.rightContext;}if (text.test(line)) {ws.push({ type: text, text: RegExp.lastMatch });line RegExp.rightContext;}}return ws;} }复制代码代码块显示 如果只是解析文本内容还是非常简单的但是技术博客嘛代码块是少不了的。为了代码关键字符的颜色显示效果为了方便阅读还得继续解析。我博客目前使用到的语言基本写了对应的解析器其实有些解析器是可以共用的比如 style方法不仅可应用到 css 上 还可以应用到类似的预解析器上比如scssless。html也一样可应用到类似的标记语言上。 const codeParse {haskell(str){},javascript(str){},html:html,css:style }; 复制代码来看一下比较有代表性的 JavaScript 解析器这里没有使用根据换行符(\n)将文本内容切割成字符串数组的方式因为有些类型需要跨行进行联合推断比如解析块方法名称判断就是如此。只能将一整块文本用正则表达式慢慢匹配消耗完。最终的结果类似上面的文本匹配结果 - 嵌套列表类型就是语法关键字常用内置方法字符串数字特殊符号等。 其实根据这个解析器可以进一步扩展和抽象一下将它作为类 C 语言族的基本框架。然后只要传递 对应语言的正则表达式规则就能解析出不同语言的结果出来比如 C#javaCGO。 javascript(str) {const comReg /^\/{2,}.*/;const keyReg /^(import|from|extends|new|var|let|const|return|if|else|switch|case|break|continue|of|for|in|Array|Object|Number|Boolean|String|RegExp|Date|Error|undefined|null|true|false|this|alert|console)(?([\s.,;(]|$))/;const typeReg /^(window|document|location|sessionStorage|localStorage|Math|this)(?[,.;\s])/;const regReg /^\/\S\/[gimuys]?/;const sysfunReg /^(forEach|map|filter|reduce|some|every|splice|slice|split|shift|unshift|push|pop|substr|substring|call|apply|bind|match|exec|test|search|replace)(?[\s\(])/;const funReg /^(function|class)\s(\w)(?[\s({])/;const methodReg /^(\w?)\s*?(\([^()]*\)\s*?{)/;const symbolReg /^([!?|\^$~%*/\-])/;const strReg /^([])([^\1]*?)\1/;const numReg /^(\d\.\d|\d)(?!\w)/;const parseComment s {const ret [];const lines s.split(/[\r\n]/g);for (let line of lines) {ret.push({ type: comm, text: line });}return ret;};let ret [];while (str) {if (/^\s*\/\*([\s\S]?)\*\//.test(str)) {str RegExp.rightContext;const coms parseComment(RegExp.lastMatch);ret ret.concat(coms);}if (/^(?!\/\*)./.test(str)) {str RegExp.rightContext;ret.push({ type: text, child:lineParse(RegExp.lastMatch) });}if(/^[\r\n]/.test(str)){strRegExp.rightContext;ret.push({type:text,text:RegExp.lastMatch});}}return ret;function lineParse(line) {let ws [];while (line) {if (/^([\s\t\r\n])/.test(line)) {ws.push({ type: text, text: RegExp.$1 });line RegExp.rightContext;}if (comReg.test(line)) {ws.push({ type: comm, text: line });break;}if (regReg.test(line)) {ws.push({ type: fun, text: RegExp.lastMatch });line RegExp.rightContext;}if (symbolReg.test(line)) {ws.push({ type: keyword, text: RegExp.$1 });line RegExp.rightContext;}if (keyReg.test(line)) {ws.push({ type: keyword, text: RegExp.$1 });line RegExp.rightContext;}if (funReg.test(line)) {ws.push({ type: keyword, text: RegExp.$1 });ws.push({ type: text, text: nbsp; });ws.push({ type: fun, text: RegExp.$2 });line RegExp.rightContext;}if (methodReg.test(line)) {ws.push({ type: fun, text: RegExp.$1 });ws.push({ type: text, text: nbsp; });ws.push({ type: text, text: RegExp.$2 });line RegExp.rightContext;}if (typeReg.test(line)) {ws.push({ type: fun, text: RegExp.$1 });line RegExp.rightContext;}if (sysfunReg.test(line)) {ws.push({ type: var, text: RegExp.$1 });line RegExp.rightContext;}if (strReg.test(line)) {ws.push({ type: var, text: RegExp.$1 RegExp.$2 RegExp.$1 });line RegExp.rightContext;}if (numReg.test(line)) {ws.push({ type: var, text: RegExp.$1 });line RegExp.rightContext;}if (/^\w/.test(line)) {ws.push({ type: text, text: RegExp.lastMatch });line RegExp.rightContext;}if (/^[^!?|\^$~%*/\-\w]/.test(line)) {ws.push({ type: text, text: RegExp.lastMatch });line RegExp.rightContext;}}return ws;} } 复制代码显示WXML 最后只要运行解析器就能生成 markdown 对应的 json 文件了然后把json加载到微信小程序的云数据库里面剩下的显示就交由小程序完成。下面就是使用 taro 编写 jsx 显示部分 View classNamearticle{lines.map(l (BlockView classNameline{l.type.search(h) 0 ( Text className{l.type}{l.text}/Text )}{l.type link ( Navigator classNamelink url{l.href} {l.text} /Navigator )}{l.type img ( Image classNamepic modewidthFix src{l.src} / )}{l.type sl ( Block Text decode classNamenum {l.num}.{ } /TextTextChild list{l.child} //Block)}{l.type ul ( Block Text decode classNamenum { } bull;{ } /TextTextChild list{l.child} //Block)}{l.type text l.child.length ( TextChild list{l.child} / )}/View{l.type code (View classNamecode{l.child.map(c (View classNamecode-line{c.type comm Text decode classNamecomm {c.text} /Text}{c.type text c.child.map(i (Block{i.type comm ( Text decode classNamecomm {i.text} /Text )}{i.type keyword ( Text decode classNamekeyword {i.text} /Text )}{i.type var ( Text decode classNamevar {i.text} /Text )}{i.type fun ( Text decode classNamefun {i.text} /Text )}{i.type text ( Text decode classNametext {i.text} /Text )}/Block))}/View))}/View)}/Block))} /View 复制代码后记 经过这个项目的磨练我的正则表达式的能力又上了一个台阶 连 环视 都已经是信手拈来了? 小程序预览 转载于:https://juejin.im/post/5cc2d703e51d453f38191d9f
http://wiki.neutronadmin.com/news/464203/

相关文章:

  • 网站建设古典风格网络营销渠道可分为
  • 乐清柳市网站建设公司iis下建立asp网站
  • 什么网站上面能接点小活做德州整站优化
  • 襄阳网站建设八零后绍兴seo网站管理
  • pc 手机自适应网站用什么做外包网易怎么样
  • 网站地图制作工具金华手机建站模板
  • 公司网站建设长春wordpress tint 2.7.0
  • 网站建设营销话术淘宝首页设计
  • 便民网站开发品牌网站建设熊掌号
  • 怎么通过贷款网站找做贷款客户如何计算网站pv
  • 免费asp网站空间电子商务应用平台包括哪些
  • 做景观私活的网站苏州朗冠网站建设公司
  • 泰州网站制作软件南宁网站建设电话咨询
  • 建设网站科目手机怎么编辑网页
  • 长沙网站建站做分享衣服网站的初衷是什么意思
  • oa软件办公系统温州百度快速排名优化
  • 做品牌网站公司黄骅市大学有哪些
  • 公司企业网站建设方案银川网站开发公司电话
  • 官网建站多少钱襄阳蒂凯网络网站建设小程序
  • 有专门做辩论的网站吗永久免费的自助建站
  • 域名备案和icp备案区别正规的关键词优化软件
  • 网站建设费入预付款什么科目wordpress调用图片上传
  • 电脑网站打不开了但是有网景区智慧旅游网站建设
  • 营销软件网站建设学做土建资料员的网站
  • seo分析网站网上商城制作需要多少钱
  • 男女做爰视频网站创新的医疗网站建设
  • 怎么网站能找人做装修事wordpress最好用php
  • 三亚网站建设费用建设官方网站的费用账务处理
  • 百度云网站开发怎样开网站wordpress js失效
  • asp自动获取网站快照 网站缩略图网站营销推广策划方案