前言
近日刷編程題過程中發現善用 replace 及正則在處理數據時能做到極大的優雅簡潔,特此記錄分享一下。
replace 基本用法
語法: replace(regexp, string || function)
這里先介紹一下 replace 第二個參數可以傳入兩種類型:
1、字符串
傳入字符串會將每次正則匹配到的結果替換為該字符串
let str = '我不是sb,你是sb嗎?';
// 第二個參數傳入字符串
str = str.replace(/sb/g, '**');
console.log(str); // 我不是**,你是**嗎?
2、回調函數
傳入回調函數會將每次正則匹配到的結果替換為該函數的返回值
let str = '我不是sb,你是sb嗎?';
str = str.replace(/sb/g, () => '**');
console.log(str); // 我不是**,你是**嗎?
replace 高級用法
1、第二個參數傳入字符串時,可以在使用 $1-$9 獲取正則捕獲組的值,例如
let str = '我喜歡你';
str = str.replace(/(我喜歡)(你)/, '$1打完游戲再打$2');
console.log(str); // 我喜歡打完游戲再打你
適用場景
用於搜索結果關鍵字高亮顯示非常舒服:
let str = '你愛我,我愛你,蜜雪冰城甜蜜蜜';
let search = '蜜雪冰城';
str = str.replace(new RegExp(`(${search})`, 'g'), '<span style="color: red;">$1</span>');
console.log(str); // 你愛我,我愛你,<span style="color: red;">蜜雪冰城</span>甜蜜蜜
2、第二個參數傳入回調函數時,除了上述基本用法外,會在該回調函數調用時傳入參數,方便對數據進行處理
回調函數調用時第一個參數為當前匹配到的值,最后一個參數為當前匹配到的值的起始下標,若有使用正則捕獲組,則將$1-$9傳入第一個參數之后,最后一個參數仍然為當前匹配到的值的起始下標
適用場景
- 模仿 Vue 數據綁定
let data = {
name: '是明啊',
hobby: ['打游戲', '編程'],
};
let str = '你好,我叫{{name}},我喜歡{{hobby.join("、")}}';
str = str.replace(/\{\{([\d\D]+?)\}\}/g, (v, k) => {
with (data) {
return eval(k);
}
});
console.log(str); // 你好,我叫是明啊,我喜歡打游戲、編程
- 英文首字母自動大寫
let str = 'I like play computer games and programming';
str = str.replace(/\s\w/g, v => v.toUpperCase());
console.log(str); // I Like Play Computer Games And Programming
- 解析 url 參數
let url = 'https://www.baidu.com?user=admin&password=123#haha';
const params = {};
url.replace(/\??(\w+)=(\w+)&?/g, function (a, k, v) {
params[k] = v;
});
console.log(params); // { user: 'admin', password: '123' }
- 顏色格式轉換
function rgb2hex(sRGB) {
if (!/^rgb\((\d{1,3},\s*){2}\d{1,3}\)$/.test(sRGB)) return '請輸入正確的rgb顏色代碼';
let color = '#';
sRGB.replace(/\d+/g, n => color += ('0' + (+n).toString(16)).slice(-2));
return color;
}
const color = rgb2hex('rgb(255, 100, 0)');
console.log(color); // #ff6400
- css 樣式轉大駝峰
function cssStyle2DomStyle(sName) {
return sName.replace(/-[a-z]/g, (v, i) => i===0?v.slice(-1):v.slice(-1).toUpperCase());
// 這里就運用了形參最后一個參數:當前匹配到的值的起始下標,處理中划線前置問題
}
const style1 = cssStyle2DomStyle('border-radius');
const style2 = cssStyle2DomStyle('-webkit-border-image');
console.log(style1); // borderRadius
console.log(style2); // webkitBorderImage
- 貨幣換算
let str = '一部手機2999人民幣,一件衣服200人民幣';
str = str.replace(/\d+人民幣/g, v => `${(v.slice(0, -3) * 0.1537).toFixed(2)}美元`);
console.log(str); // 一部手機460.95美元,一件衣服30.74美元
let str = '一部手機2999人民幣,一件衣服200人民幣';
str = str.replace(/(\d+)(人民幣)/g, (v, $1, $2) => `${($1 * 0.1537).toFixed(2)}美元(${$1}${$2})`);
console.log(str); // 一部手機460.95美元(2999人民幣),一件衣服30.74美元(200人民幣)
- 時間顯示處理
function formatDate(t, str) {
var obj = {
yyyy: t.getFullYear(),
yy: ('' + t.getFullYear()).slice(-2),
M: t.getMonth() + 1,
MM: ('0' + (t.getMonth() + 1)).slice(-2),
d: t.getDate(),
dd: ('0' + t.getDate()).slice(-2),
H: t.getHours(),
HH: ('0' + t.getHours()).slice(-2),
h: t.getHours() % 12,
hh: ('0' + t.getHours() % 12).slice(-2),
m: t.getMinutes(),
mm: ('0' + t.getMinutes()).slice(-2),
s: t.getSeconds(),
ss: ('0' + t.getSeconds()).slice(-2),
w: ['日', '一', '二', '三', '四', '五', '六'][t.getDay()]
};
const reg = /y{2,4}|m{1,2}|d{1,2}|h{1,2}|s{1,2}|w/ig;
return str.replace(reg, k => obj[k]);
}
const date1 = formatDate(new Date(1627430400000), 'yyyy-MM-dd HH:mm:ss 星期w');
const date2 = formatDate(new Date(1627430400000), 'yy-M-d H:m:s 星期w');
console.log(date1); // 2021-07-28 08:00:00 星期三
console.log(date2); // 21-7-28 8:0:0 星期三