當我問表單校驗的面試題時,我期望得到什麼樣的答案
面試題
校驗用戶名表單,長度為8-10位的只包含數字和字母的字元串,用JavaScript實現一個校驗函數。
1 解決過程
1.1 首先確認題目需求(幾乎沒有人確認過,當然也沒有人寫對過)
1.1.1 題目要求
- 長度8-10位
- 只包含數字和字母
- JS校驗函數
1.1.2 Tips
- 幾乎沒人確認過
- 沒人寫對過
- 如果這裡有問題,後面肯定對不了
1.2 其次分析思路(轉換為可以寫代碼的等價邏輯表達,也沒人寫對過)
1.2.1 等價邏輯轉換一
- 包含字母
- 包含數字
- 只能是數字和字母
- 長度8-10位
1.2.2 等價邏輯轉換二
- 不 全為數字
- 不 全為字母
- 只能是數字和字母
- 長度8-10位
1.2.3 等價邏輯轉換三
- 所有字元ASCII碼在數字和字母的範圍內
- 長度8-10位
1.2.4 Tips
- 即使前面需求理解清楚,這裡轉換不等價也得不到正確的結果
- 有了這裡面的等價分解,最基本的TestCase也就有了,便於後面做校驗
- 即使寫不出代碼來,這裡能說清楚也行
- 說不清楚也行,需要能看到不斷嘗試,積極思考的過程
1.3 然後是核心代碼實現(清一色的正則,我們也先說正則)
1.3.1 使用零寬正向先行斷言
1.3.1.1 代碼實現
/^(?=.*d.*)(?=.*[a-zA-Z].*)[0-9a-zA-Z]{8,10}$/.test(str)
1.3.1.2 代碼解釋
(?=)表達正向先行斷言,滿足條件的其他匹配結果才為真,即括弧內的表達式匹配整個匹配結果才為真- 可以出現在代碼的任意位置
- 不佔用最終的匹配寬度
- 這裡表達既包含數字又包含字母的只包含數字和字母的8-10位的字元串
1.3.1.3 邏輯表達
- 包含數字
- 包含字母
- 8-10位的數字和字母的組合(全匹配)
1.3.2 使用零寬負向先行斷言
1.3.2.1 代碼實現
/^(?!d+$)(?![a-zA-Z]+$)[0-9a-zA-Z]{8,10}$/.test(str)
1.3.2.2 代碼解釋
(?!)表達負向先行斷言,滿足非條件的其他匹配結果才為真,即括弧內的表達式不匹配整個匹配結果才為真- 可以出現在代碼的任意位置
- 不佔用最終的匹配寬度
- 這裡表達不全為數字且不全為字母的只包含數字和字母的8-10位的字元串
1.3.2.3 邏輯表達
- 不全為數字的(全匹配)
- 不全為字母的(全匹配)
- 8-10位的數字和字母的組合(全匹配)
1.3.2.4
1.3.3 如果不知道上面的方式,可以拆分一下
1.3.3.1 代碼實現
!/^d+$/.test(str) && !/^[a-zA-Z]+$/.test(str) && /^[0-9a-zA-Z]{8,10}$/.test(str)
1.3.3.2 代碼解釋
- 不解釋了,直接的邏輯表達
1.3.3.3 邏輯表達
- 不全為數字的(全匹配)
- 不全為字母的(全匹配)
- 8-10位的數字和字母的組合(全匹配)
1.3.4 如果不知道正則怎麼玩,也可以用字元判斷的方式
1.3.4.1 代碼實現
//考慮記不住ASCII碼var rangeChars = 09azAZ;var char0Code = rangeChars.charCodeAt(0),char9Code = rangeChars.charCodeAt(1),charaCode = rangeChars.charCodeAt(2),charzCode = rangeChars.charCodeAt(3),charACode = rangeChars.charCodeAt(4),charZCode = rangeChars.charCodeAt(5);Array.from(str).every(char => { return 0 <= char && char <= 9 || a <= char && char <= z || A <= char && char <= Z });Array.from(str).some(char => { return 0 <= char && char <= 9});Array.from(str).some(char => { return a <= char && char <= z || A <= char && char <= Z });8 <= str.length && str.length <= 10
1.4 最後是結果的輸出
export const validationUtil = { isNameValid:(str) => { //調用isNameValid 的同時,不應該有判斷undefind,判斷null的過程,表單取出來的不會有這倆值 str += ; str = str.trim(); return /^(?!d+$)(?![a-zA-Z]+$)[0-9a-zA-Z]{8,10}$/.test(str); }}
2 常見問題
- 校驗不寫trim
- 正則不寫首尾匹配
- /^[0-9a-zA-Z]{8,10}$/ 作為題目結果
- 自己寫出來的正則,自己也不知道啥意思
3 參考資料
3.1 正則書籍
- 基礎
- 學習正則表達式
- 正則表達式必知必會
- 神奇的匹配
- 進階
- 精通正則表達式
- 正則指引
3.2 正則工具
- 分析調試工具
- Regex Buddy, Regex Magic
- Match Tracer
- 正則表達式101
- regex101
- regexr
- 可視化分析
- regulex
- regexper
推薦閱讀:
※Hulu機器學習問題與解答系列 | 二十五:初識生成式對抗網路(GANs)
※總結 is 和 == 的區別
※軟通動力軟體測試面試題庫
※面試時如何回答「你對加班的看法」?
