摘要:對于正則之前一直是一個百度程序員也許超過一半甚至更多的程序員也是那么這次來學習一下正則表達式事出有因這部分介紹一下需求的由來與主要內容無關工作上有了這樣的需求端從來的數據格式是也就是文章內容并夾雜著諸多標簽和嵌套然而正在開發的是項目的標簽
對于正則之前一直是一個"百度程序員", 也許超過一半甚至更多的程序員也是, 那么這次來學習一下正則表達式.
事出有因這部分介紹一下需求的由來, 與主要內容無關.
工作上有了這樣的需求:
web端從ueditor來的數據格式是html, 也就是
文章內容
, 并夾雜著諸多標簽和嵌套.然而正在開發的是react-native項目, rn的標簽和html完全不兼容, 是View, Text, Image等.
那么把從web存入的數據讀取到rn上就出了大麻煩, 甚至有些地方要進行跳轉, 有些圖片要顯示, 那么怎么辦呢.
通過百度"js如何驗證郵箱"已經無法滿足需求了, 只能學一下了.
目標萬事有目標, 我們要把一下內容轉換成rn的內容:
嘿嘿嘿拖過來的圖片哦
abcd
轉換結果是:
嘿嘿嘿 拖過來的圖片哦 a b ...
本文會從零基礎出發達成這個目標.
講解順序: 正則介紹 => 正則語法系統 => 簡單的例子講解 => 嘗試實現目標以及碰到的問題 => 實現目標
什么是正則初中時候學的通配符, 用?代表一個任意字符, 用*代表任意個任意字符來進行搜索, 正則也是如此. 比如:
123[abc]匹配以下哪組字符?
123c
123d
123e
123f
選了1的朋友你已經知道正則是什么了. 123[abc]就是正則, 代表匹配內容為: 前三個字符分別為123, 第四個字符是abc中的一個, 這個正則遇到123a, 123b, 123c都可以匹配成功, 其他任何都匹配失敗.
正則語法百度了正則表達式看到的東西都用了很多術語, 讓人有點犯渾. 我經過學習把正則抽象為兩個部分: 內容和修飾.
看到一長串正則覺得稀里嘩啦, 但是里面的每個符號一定都屬于內容或是修飾.
內容內容的形式有3種:
直接匹配: 舉例就是剛才的123[abc]中的123, 這種匹配需要完全吻合才能匹配, 123就唯一匹配123.
范圍匹配: 用中括號表示, 也就是剛才例子中的[abc]. 這種情況也就是三選一. 任意匹配a或b或c, 而不是匹配abc. 還有兩種形式: 加-來表示范圍, 比如[a-z]; 表示排除范圍內的^, 比如[^abc]
匹配并選擇緩存到子匹配: 用圓括號表示, 圓括號中的內容語法是"直接匹配"但會被記入緩存作為子匹配, 我記得我最初接觸正則就是url rewrite, 寫了url正則之后用$1, $2來重寫url.
在范圍匹配中, 我們經常會用: 數字/字母, 也就是[0-9], [a-zA-Z], 但是經常用到重復地寫麻煩又看不能裝逼了, 所以產生了一些快捷方式: d代表[0-9], w代表[0-9a-zA-Z_]這正好是常用的用戶名和密碼的規則.
這里深入一下圓括號匹配的兩個點. 作為拓展, 可以先不看一下的內容直接到下一部分.
因為圓括號中可以用|符號來表示或的關系, 但有時候又不想被加入緩存. 于是可以用?:來表示不需要緩存. 例子:hello (?:world|regular expression), 用來匹配hello world或者hello regular expression, 但又不需要把world儲存為緩存.
如果之前已經用圓括號, 那么期望之后出現同樣的內容, 可以用1這樣加數字來表示. 舉個例子: 單引號和雙引號, 我們要匹配"123"或者"123", 但是要保持引號一致. ("|")1231就可以解決問題.
修飾我把修飾部分分為數量修飾和邊界修飾.
數量修飾: 符號為{}, 想到了谷歌: go{2,4}gle這個正則可以匹配google, gooogle, goooogle, 代表這個o可以匹配2或者4次. 當然只是為了舉例可以枚舉, 因為go{2,}gle代表可以無限個o, 這樣舉例不方便.
與之前的范圍匹配一樣, 數量修飾也有快捷符號: ?代表{0,1}, *代表{0,}, +代表{1,}. 都很形象, 不用死記, 就像剛才的d for digital, w for word. 看過一個例子: colou?r 這里的?表示可有可無, 美式和英式的拼寫都可以匹配.
另外在"無上限"的數量的右邊加?代表不貪婪匹配, 會匹配數量最少的內容. 舉例: a+匹配aaaaa的結果為aaaaa, a+?匹配aaaaa的結果為a.
邊界修飾: ^表示字符串的頭, $表示字符串的尾, 表示字母與空格間的位置. 用來給匹配定位, 具體用法在實際中操作就會有具體感受了.
另外, 正則有一種匹配模式是m, 多行匹配模式, 這個情況里^和$也能匹配每一行的開頭和結尾.
javascript相關函數首先明確正則是"正則表達式"與"字符串"發生的匹配關系.
js有個對象是RegExp, 使用方法是new RegExp(pattern, mode), 或者是用/包裹的字面量: /pattern/mode.
這里發現提到了mode匹配模式, 一共三種:
g: 全局匹配, 匹配到一次不會停止, /a/匹配aaa, 如果沒有g結果是一個a, 有g結果是3個a.
i: 忽略大小寫.
m: 多行模式. 和之前提到的有聯動.
三個模式不互斥, 疊加的, 也就是可以new RegExp(patter, "gin").
正則的方法有:
.test(): 返回是否匹配成功, true或者false.
.exec(): 失敗返回null, 成功返回數組, 位置0是匹配內容, 之后是圓括號匹配的內容. 要注意的是exec是忽略"g"模式的.
字符串的方法:
.replace(pattern, replacement): replacement可以字符串或方法, 方法的話參數是匹配到的內容.
.match(pattern): 返回數組, 所有匹配到的內容.
分析一些簡單常用的例子 是否小數function isDecimal(strValue ) { var objRegExp= /^d+.d+$/; return objRegExp.test(strValue); }
d代表數字, +代表至少有1個數字, .轉移小數點.
連起來看就是: 至少一個數字(d+) 小數點(.) 至少一個數字(d+) .
^和$代表頭尾, 真個字符串是小數的全部, 而不是包含小數.
是否中文名function ischina(str) { var reg=/^[u4E00-u9FA5]{2,4}$/; /*定義驗證表達式*/ return reg.test(str); /*進行驗證*/ }
這個范圍是中文的編碼范圍: [u4E00-u9FA5], {2,4}匹配2~4個. 也就是匹配2~4個中文.
是否八位數字function isStudentNo(str) { var reg=/^d{8}$/; /*定義驗證表達式*/ return reg.test(str); /*進行驗證*/ }是否電話號碼
function isTelCode(str) { var reg= /^((0d{2,3}-d{7,8})|(1[3584]d{9}))$/; return reg.test(str); }
分兩個部分: 座機號和手機號, 用|隔開了.
座機號: 0開頭的三位數或四位數 短杠 7~8位數字.
手機號: 第一位1, 第二位3584的一個, 剩下由9個數字湊滿11位電話.
郵箱地址function IsEmail(str) { var reg=/^([a-zA-Z0-9_-])+@([a-zA-Z0-9_-])+(.[a-zA-Z0-9_-])+$/; return reg.test(str); }邁向目標
這個章節開始整理實現需求的思路.
先回憶一下正則的規則, 其實很簡單, 和加減乘除一樣, 有各種符號: [], (), |, -, {}, +, *, ?. 當然也可以很復雜, 因為也和加減乘除一樣, 可以嵌套, 而正則的符號本來就多, 嵌套起來更是暈, 有一些符號在不同地方有不同作用, 比如和^.(思考題: 分析一下這兩個符號有哪些作用, 在什么場景).
那么我們的目標是: 把一段html分析稱rn的標簽.
因為rn沒有parse的功能, 所以不可以使用replace. (replace是代碼高亮的常用手段).
所以我們必須把html分解成js對象, 再從js對象里去分析輸出rn標簽.
因為html標簽分為多種, 為了保證完整性和可維護性, 要把各個標簽的正則分開寫, 也便于之后在分析每個片段的時候來取子匹配, 比如img標簽的src, a標簽的href.
經過研究, 正則是不可以拼接的, 只有字符串可以拼接. 所以我們要把不同標簽的正則寫成字符串, 再在需要的時候拼接. new RegExp(pattern)的pattern參數是可以接受字符串的.
匹配text的難題與正則匹配的動作分析眾所周知, 在html里的text是可以光禿禿的(在rn里必須加上Text標簽). 那么如何匹配這光禿禿的東西呢, 我開始想了一個辦法: 因為text都在標簽之外, 也就是"夾在>和<中的字符", 或者在開頭(^)和<間的, 或者>和結尾($)間的. 結果標簽全都匹配不到了.
原因是這樣的, 如果有"g"的模式, 匹配的過程是這樣的:
進行第一次匹配, 匹配成功后把匹配部分排除待匹配內容.
進行第二次匹配, 匹配成功后把匹配部分排除待匹配內容.
直到匹配失敗, 返回所有結果.
舉個例子:
"applebananaapple".match(/(apple|banana)/g)
結果是["apple", "banana", "apple"]
如果把banana的最后一個字母和apple的第一個字母寫成一個:
"applebananapple".match(/(apple|banana)/g)
那么結果就是["apple", "banana"]了.
反而利用了這個特點, 把text的正則寫成: 不包含<>/ ([^<>/]+), 并添加在最后一個匹配, 就能正確地匹配出text啦.
揭曉答案寫得急促也許有遺漏, 最后貼上完成需求的代碼, 語言是rn, 在map輸出的時候帶著一些項目業務的邏輯請無視.
import React, {Component} from "react" import {Text, View, Image, Platform, StyleSheet, TouchableOpacity} from "react-native" import {ENVS} from "../../config/apiHost" /* 必須props: @html: html內容 可選props: @style: 字體style; @magnifyImg: 顯示大圖 */ const regex = { // "_" for close tag p: `]*?>`, _p: `
`, span: `]*?>`, _span: ``, br: `
`, a: `]*?href=("|")([^>]+?)1[^>]*?>([^<]+?)`, // $1 是標點符號用來處理匹配 $2 href的帶引號的內容 $3 文件名(a標簽的innerText), img: ``, // $1 標點符號 $2 src的內容 text: `[^<>/]+`, // 匹配剩下的, 一定要放在最后 } const tobeRemoved = new RegExp(`(?:${[regex.p, regex._p, regex.span, regex._span, regex.br].join("|")})`, "g") const parseToAst = new RegExp(`(?:${[regex.a, regex.img, regex.text].join("|")})`, "g") export default class Parsed extends Component { render () { let str = this.props.html.trim() if (!str) { return (html attr not passed to component "parseHtml" ) } matches = str.replace(tobeRemoved, "").match(parseToAst) return ({matches.map((block, index) => { for (let [key, value] of Object.entries(regex)) { let res = new RegExp(value).exec(block) if (res) { if (key === "text") { return ( ) } }{block} ) } if (key === "a") { if (res[2].includes("files")) { // 判斷附件 if (/[jpg|png|jpeg]/i.test(res[3])) { // 判斷圖片 let imgId = res[2].match(/d+/)[0] return ({this.props.magnifyImg && this.props.magnifyImg(ENVS.production.api_base_url + "/files/" + imgId)}} > ) } } } if (key === "img") { return ({this.props.magnifyImg && this.props.magnifyImg(res[2])}}> ) } } } })}
原文地址
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/94696.html
摘要:正則表達式實現快速古詩匹配作者簡介是推出的一個天挑戰。數據匹配操作使用基礎參考文檔項目源碼分析正則找出匹配的詩句替換高亮的標簽構造值會返回帶搜索關鍵字的新數組。執行對大小寫不敏感的匹配。 Day06 - Fetch、filter、正則表達式實現快速古詩匹配 作者:?liyuechun 簡介:JavaScript30 是 Wes Bos 推出的一個 30 天挑戰。項目免費提供了 30 ...
摘要:正則表達式實現快速古詩匹配作者簡介是推出的一個天挑戰。數據匹配操作使用基礎參考文檔項目源碼分析正則找出匹配的詩句替換高亮的標簽構造值會返回帶搜索關鍵字的新數組。執行對大小寫不敏感的匹配。 Day06 - Fetch、filter、正則表達式實現快速古詩匹配 作者:?liyuechun 簡介:JavaScript30 是 Wes Bos 推出的一個 30 天挑戰。項目免費提供了 30 ...
摘要:正則表達式實現快速古詩匹配作者簡介是推出的一個天挑戰。數據匹配操作使用基礎參考文檔項目源碼分析正則找出匹配的詩句替換高亮的標簽構造值會返回帶搜索關鍵字的新數組。執行對大小寫不敏感的匹配。 Day06 - Fetch、filter、正則表達式實現快速古詩匹配 作者:?liyuechun 簡介:JavaScript30 是 Wes Bos 推出的一個 30 天挑戰。項目免費提供了 30 ...
摘要:監測字符串變化聲明字符串輸入變化的獲取對象更新顯示數據事件監聽通過監聽鍵盤輸入的變化,當鍵盤彈起時,調用函數。 (Node+Vue+微信公眾號開發)企業級產品全棧開發速成周末班首期班(10.28號正式開班,歡迎搶座) 作者:?liyuechun 簡介:JavaScript30 是 Wes Bos 推出的一個 30 天挑戰。項目免費提供了 30 個視頻教程、30 個挑戰的起始文檔和 3...
閱讀 2473·2021-11-24 09:39
閱讀 3406·2021-11-15 11:37
閱讀 2251·2021-10-08 10:04
閱讀 3965·2021-09-09 11:54
閱讀 1883·2021-08-18 10:24
閱讀 1034·2019-08-30 11:02
閱讀 1793·2019-08-29 18:45
閱讀 1651·2019-08-29 16:33