搜尋器

Reference: JavaScript 30

先備知識

範例

form.search-form
 input.search(type='text', placeholder='City or State')
 ul.suggestions
 li Filter for a city
 li or a state
html
 box-sizing: border-box
 background: #ffc600
 font-family: 'helvetica neue'
 font-size: 20px
 font-weight: 200

*
 box-sizing: inherit
 &:before, &:after
 box-sizing: inherit

input
 width: 100%
 padding: 20px

.search-form
 max-width: 400px
 margin: 50px auto

input.search
 margin: 0
 text-align: center
 outline: 0
 border: 10px solid #F7F7F7
 width: 120%
 left: -10%
 position: relative
 top: 10px
 z-index: 2
 border-radius: 5px
 font-size: 40px
 box-shadow: 0 0 5px rgba(0, 0, 0, 0.12), inset 0 0 2px rgba(0, 0, 0, 0.19)

.suggestions
 margin: 0
 padding: 0
 position: relative
 /*perspective:20px;
 li
 background: white
 list-style: none
 border-bottom: 1px solid #D8D8D8
 box-shadow: 0 0 10px rgba(0, 0, 0, 0.14)
 margin: 0
 padding: 20px
 transition: background 0.2s
 display: flex
 justify-content: space-between
 text-transform: capitalize
 &:nth-child(even)
 transform: perspective(100px) rotateX(3deg) translateY(2px) scale(1.001)
 background: linear-gradient(to bottom, #ffffff 0%, #EFEFEF 100%)
 &:nth-child(odd)
 transform: perspective(100px) rotateX(-3deg) translateY(3px)
 background: linear-gradient(to top, #ffffff 0%, #EFEFEF 100%)

span.population
 font-size: 15px

.details
 text-align: center
 font-size: 15px

.hl
 background: #ffc600

.love
 text-align: center

a
 color: black
 background: rgba(0, 0, 0, 0.1)
 text-decoration: none
const endpoint = 'https://gist.githubusercontent.com/Miserlou/c5cd8364bf9b2420bb29/raw/2bf258763cdddd704f8ffd3ea9a3e81d25e2c6f6/cities.json';

const cities=[];

//blob用來指稱原始資料
//轉換成JSON資料
fetch(endpoint)
 .then(blob => blob.json())
 .then(data => cities.push(...data))

function find(word, cities){
 
 return cities.filter(place => {
 const regex=new RegExp(word, "gi");
 return place.city.match(regex) || place.state.match(regex)
 })

}

function commas(x){
 return x.toString().replace(/B(?=(d{3})+(?!d))/g, ",");
}


function display(){
 const match=find(this.value, cities);
 const html=match.map(place => {
 const regex=new RegExp(this.value, "gi");
 const cityName=place.city.replace(regex, `<span class="hl">${this.value}</span>`);
 const stateName=place.state.replace(regex, `<span class="hl">${this.value}</span>`);
 
 return `
 <li>
 <span class="name">${cityName}, ${stateName}</span>
 <span class="population">${commas(place.population)}</span>
 </li>
 `
 }).join("");
 
 
 suggestions.innerHTML=html;
}

const search=document.querySelector(".search");
const suggestions=document.querySelector(".suggestions");


search.addEventListener("change", display);
search.addEventListener("keyup", display);

Display

CODEPEN

regex【i】不區別大小寫

功能

讓字串不區分大小寫,也能通過正規表達式檢査。
應用實例:搜尋不用區分大小寫,也能找到同樣的内容。

類似的東西:regex【g】找出所有

範例

方法一【/i】

i代表 insensitive ,對大小寫不敏感。

const regex=/apple/i;

const str1="APPLE";
const str2="Apple";
const str3="apple";

str1.match(regex);//["APPLE"]
str2.match(regex);//["Apple"]
str3.match(regex);//["apple"]
//不論大小寫(或混用)都能通過驗證

方法二【new RegExp】

使用時機:需要檢査的字串不是固定値,而是變數時(像是使用者鍵入的搜尋字詞)

寫法跟【/i】不同,但是效果相同。

const regex=new RegExp("apple", "i");

const str1="APPLE";
const str2="Apple";
const str3="apple";

str1.match(regex);//["APPLE"]
str2.match(regex);//["Apple"]
str3.match(regex);//["apple"]

match() 與 test()

功能

兩者都是搭配正規表達式的Method

match()

字串.match(正規表達式);
//回傳比對出的部分字串結果
//若比對不到東西,則回傳null

const str="apple";
const check=/[a-c]/;

str.match(check);//["a"]

test()

正規表達式.test(字串);
//有比對到回傳true,沒有則回傳false

const str="apple";
const check=/[a-c]/;

check.test(str);//true

正規表達式

説明

正規表達式,是專門用來處理字串邏輯的條件語法。
常常用在 input 表單上,檢査使用者輸入的内容有沒有符合特定格式。
諸如信用卡號格式驗證,密碼強度驗證等等。

相關方法:match(),test()

語法

宣告正規表達式

正規表達式的前後要各用1個斜線/包起來(有點像字串需要用”包起來)。

const str="abcde";
const check=/abc/;

str.match(cri);//["abc"]
//回傳 被找到的字串
if(str.match(cri)){
 console.log(true);
 //↑通常驗證表單會寫成這個形式,裡面放通過驗證後的動作
}else{
 console.log(false)
}//true

尋找某區間内文字

設定檢索區間: [a-e]
a為開始値,e為終止値。

const str="apple";
const check=/[a-c]/;//尋找有沒有 a,b,c 這3個字母
//※寫成/[a-c]/g會比較好(下面會説明)
//※也可以比對多重區間(下面説明)

str.match(check)//["a"]

if(str.match(cri)){
 console.log(true);
}else{
 console.log(false);
}//true ←但只有 a 有被找到而已,pple並沒有被找到

/*****注意*****
※這個例子match是寬鬆尋找方法,只要有1個字元被找到,就會跑出true
*************/

尋找全部【/g】

參考這篇文章

一般情況下,match只會1次比對一個字串字元而已,所以回傳値只會吐出第1項符合的字元。
如果要叫他吐出所有,就要使用/g←放在正規表達式的最後面

※但如果是用 if(str.match(check)) 的話不使用 /g 也沒差

const str="apple";
const check=/[a-e]/;
const check2=/[a-e]/g;//尋找全部寫法


str.match(check);//["a"]
str.match(check2);//["a", "e"]←這樣寫就可以一條一條找出所有符合的字元了

/****比對多重區間***/
const check3=/[a-eo-p]/g//←直接接下去加入就好

str.match(check3);//["a", "p", "p", "e"]

尋找數字與數字字符【\d】

有2種方法可以找到數字

  • 設定 0-9 的區間
  • 正規字符【\d】
const str="apple123";
const check=/[0-9]/g
const check2=/\d/g; //\d效果同等於[0-9]


str.match(check);//["1", "2", "3"]
str.match(check2);//["1", "2", "3"]

檢査數字長度

使用大括號{}指定該字元必須出現幾次

const str="123456";
const check=/\d{4}/;//{4}表示數字(\d)要連續出現4次←4位數字

str.match(check);//["1234"]

if(str.match(check)){
 console.log(true);
}else{
 console.log(false);
}//ture
/*****
str="123456"→true
str="1234"→true
str="12"→false

只有當str不足4位數字時才會回報false(match找不到匹配値,回傳null)
str滿足或超過4位數都會回傳true
※那要怎麼寫手機號碼驗證!←下面告訴你
*****/

設定嚴格的條件:使用開始【^】與結束【$】字符

在上例中可以發現,只有當字串不滿足條件時才會報 false ,剛好符合或超過條件的清況都會回報 true 。

但某些情況下,我們需要非常精確的格式,比如

  • 手機號碼必須是 10 位數字
  • 信用卡號必為 4位數-4位數-4位數-4位數
  • 身份證字號為 1大寫英文 + 9 為數字

所以我們必須更進階地規定條件,不足或超出條件者都必須是 false。

以下為嚴格化寫法

  • 在開頭加入開始字符^
  • 結尾加入結束字符$
//驗證手機號碼
const str1="0912345678";
const str2="0912";
const str3="09123456789999"
const check=/^\d{10}$/;

str1.match(check); //["0912345678"]
str2.match(check); //null
str3.match(check); //null

//進階:規定前2碼為09

const check2=/^09\d{8}$/; //指定09跟後面的8碼條件不用任何東西連接,直接加上就行

str1.match(check2); //["0912345678"]

英數字集符號【\w】

如同 \d 為 [0-9] 的簡寫一般,
\w 則為 [a-zA-Z0-9_] 的簡寫。

可以檢查所有英文大小寫字母,底線,以及數字

const str="ianchen_0419";

const check=/\w/g;
const check2=/[a-zA-Z0-9_]/g;
//這兩個效果一樣

str.match(check);//["i", "a", "n", "c", "h", "e", "n", "_", "0", "4", "1", "9"]
str.match(check2);//["i", "a", "n", "c", "h", "e", "n", "_", "0", "4", "1", "9"]

 

可有可無的條件【?】

『使用者名稱可以包含減號-』

這樣的情況下,不論字串有無減號-,皆可滿足條件。
因此減號-是一個可有可無的條件。

在減號-後面加上問號 ? ,便可以構成可有可無的驗證式

const str1="ianchen";
const str2="ian-chen";
const str3="ian--chen";
const str4="-ianchen";
const str5="ianchen-";

const check=/\w-?\w/;
const check2=/^\w-?\w$/;
//用check2的話5個str都會是null,因為check2必須是【1字母 + 有無底線皆可 + 1字母】的組合才行。


str1.match(check);//["ia"]
str2.match(check);//["ia"]
str3.match(check);//["ia"]
str4.match(check);//["-i"]
str5.match(check);//["ia"]
//結論:5種情況都可以true

比對特殊字元:前置反斜線\

Regex特殊字元【.^$?】

這些字元都是Regex特殊字符,帶有特殊的意義。
若要單純比對這些符號,必須前置反斜線\以做區別。

const str1="$";
const str2="^";
const str3=".";
const str4="?";

const check1=/\$/;
const check2=/\^/;
const check3=/\./;
const check4=/\?/;

str1.match(check1);//["$"]
str2.match(check2);//["^"]
str3.match(check3);//["."]
str4.match(check4);//["?"]

比對很多次【+】

重複比對【+】前面的東西很多次

const str="ianchen_0419";
const check=/\w+/;
//重複比對英文字元(←【+】前面的)很多次,直到比對不了為止

str.match(check);//["ianchen_0419"]

有後面再比對前面【?=】

a(?=b)→如果有找到b的話,再檢查前面有沒有a,並且比對出a
【?=b】要使用括號包起來

const str1="ianchen0419";
const str2="ianchen"
const str3="0419ianchen";
const check=/[a-z]+(?=\d)/;
//後面有數字的話,再比對前面有沒有英文
//然後把所有的英文都找出來【+】

str1.match(check);//["ianchen"]
str2.match(check);//null ←這個因為後面找不到數字所以沒辦法比對英文
str3.match(check);//null ←這個因為數字前面沒有英文所以一樣無法

沒有後面再比對前面【?!】

a(?!b)→如果沒有找到b的話,再檢查前面有沒有a,並且比對出a
【?!b】要使用括號包起來

使用情境:給數字加上分隔逗號,每3碼加一個逗號,但是要從最末位往前數(所以要確保後面沒有落單的數字)

【例】1,234,567,890

const str1="ianchen0419";
const str2="ianchen"
const str3="0419ianchen";
const check=/[a-z]+(?!\d)/;
//後面沒有數字的話,再比對前面有沒有英文
//然後把所有的英文都找出來【+】

str1.match(check);//null ←這個因為後面有數字了所以不能比對前面的英文
str2.match(check);//["ianchen"]
str3.match(check);//["ianchen"]

找出英文邊界【\b】

※前提,英文句子要用空格隔開單字

【\b\w】→找到每個單字字首
【\w\b】→找到每個單字字尾

const str="this is a apple";//必須要有空格
const check1=/\b\w/g;//找字首
const check2=/\w\b/g;//找字尾

str.match(check1);//["t", "i", "a", "a"]
//"this is a apple"

str.match(check2);//["s", "s", "a", "e"]
//"this is a apple"

找出非英文邊界【\B】

用途:數字,符號等等

const str="1234567890";
const check1=/\B\d{3}/g;//每3個字斷開(從後面開始數)
const check2=/\d{3}\B/g;//每3個字斷開(從前面開始數)


str.match(check1);//["234", "567", "890"]
str.match(check2);//["123", "456", "789"]

英文數字逗點

【例】1234567890→1,234,567,890

function commas(x){
 return x.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
 //①從最末位往前數3碼(後面沒有數字的話,比對出3個數字)
 //②一直數一直數
 //③符合①就給他分隔符號
 //④\B比對非英文字的邊界,如果沒有\B的話會變成",123,456,789"
 //取代所有分隔符號為","

}

線上練習網站:RegexOne