iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 22
0

今日kata

原始題目如下:(5kyu)
… a man was given directions to go from one point to another. The directions were "NORTH", "SOUTH", "WEST", "EAST". Clearly "NORTH" and "SOUTH" are opposite, "WEST" and "EAST" too.

Going to one direction and coming back the opposite direction right away is a needless effort. Since this is the wild west, with dreadfull weather and not much water, it's important to save yourself some energy, otherwise you might die of thirst!

翻譯:
有一份方位指示,是一連串的東西南北組合,其中東-西 南-北為相反方向,相反方向相鄰的指示存在,是不必要的,也為了行路人(?)的體力著想,請協助重新整理這份指南。

範例:

["NORTH", "SOUTH", "SOUTH", "EAST", "WEST", "NORTH", "WEST"] ==>  ["WEST"]
["EAST", "EAST", "WEST", "NORTH", "WEST", "EAST", "EAST", "SOUTH", "NORTH", "WEST"] ==> ["EAST", "NORTH"]

同理消括號系列題目,NORTH SOUTH相鄰要消除、EAST WEST相鄰要消除!


構想&解法

function dirReduc(arr) {
  let pair = {
    'NORTH': 'SOUTH',
    'SOUTH': 'NORTH',
    'WEST': 'EAST',
    'EAST': 'WEST'
  }
  let stack = []
  for (let i = 0; i < arr.length; i++) {
    stack.length === 0 ? stack.push(arr[i]) :
      pair[(stack[stack.length-1])] === arr[i] ? stack.pop() : stack.push(arr[i])
  }
  return stack
}

解法類似找出括號是否成對,相對方向的南北/東西可以互消。

宣告stack陣列負責存放結果以及一pair物件定義4個屬性NORTH SOUTH WEST EAST

一一遍歷arr中的方位,若stack為空則放入arr[i],反之判斷stack最尾端的元素是否與arr[i]為相對方位,若是則移除stack最尾端元素,反之stack放入arr[i]


其他解法觀摩

function dirReduc(arr) {
  var str = arr.join(''), pattern = /NORTHSOUTH|EASTWEST|SOUTHNORTH|WESTEAST/;
  while (pattern.test(str)) str = str.replace(pattern,'');
  return str.match(/(NORTH|SOUTH|EAST|WEST)/g)||[];
}

出乎意料的解法! /images/emoticon/emoticon02.gif
將arr合併成一字串,使用RegExp檢測是否有符合的字串片段出現,若有就取代成空字串,最後使用match()回傳符合pattern的陣列。

  • 比對的pattern為/NORTHSOUTH|EASTWEST|SOUTHNORTH|WESTEAST/ 有符合其中一種字串即可
  • pattern.test(str)為檢測str是否有匹配pattern,回傳true/false
  • str.match(regexp),且flag為global的話,會以陣列方式回傳在str中有match到結果

整理用法

整理可使用正規表示式的Method以及正規表示式物件本身的Method

正規表示式.exec()

語法:regexp.exec(str)

exec()會搜尋str是否有符合的特定字串,回傳結果陣列或是null

  • 若沒有使用g flag,regexp.exec(str)會回傳第一個匹配的結果,效果如同str.match(regexp)
    (沒有g即代表regexp.lastIndex被設為0)

  • 若有使用g flag:

    • regexp.exec(str)會回傳第一個匹配結果,並且以regexp.lastIndex屬性來儲存下一次執行exec()要開始搜尋的位置
    • 會根據lastIndex繼續往下搜尋,持續更新regexp.lastIndex
    • 如果沒有匹配的結果,regexp.exec()本身會回傳null,並將regexp.lastIndex設為0,代表regexp不繼續搜尋了。
let str = 'More about JavaScript at https://javascript.info';
let regexp = /javascript/ig;
let result;

while (result = regexp.exec(str)) {
  alert( `Found ${result[0]} at position ${result.index}, ${regexp.lastIndex}`  );
  // Found JavaScript at position 11,21 then
  // Found javascript at position 33,43
}

利用regexplastIndex屬性,可以指定開始搜尋的位置

let str = 'Hello, world!';
let regexp = /\w+/g; // without flag "g", lastIndex property is ignored
regexp.lastIndex = 5; // search from 5th position (from the comma)
alert( regexp.exec(str) ); // world

正規表示式.test()

語法:regexp.test(str)

test()會搜尋str,根據有無符合結果,回傳true/false

範例:

let str = "I love JavaScript";
alert( /love/i.test(str) ); // true

字串.match()

語法:str.match(regexp)

搜尋str是否有和regexp匹配的結果

有三種模式(?):

  1. regexp沒有g flag,會回傳第一個匹配到的結果,並以陣列回傳
    (陣列還包含capturing groupsindex(即match到的位置)、input(即str自己))
let str = "I love JavaScript";
let result = str.match(/Java(Script)/);
alert( result[0] );     // JavaScript (full match)
alert( result[1] );     // Script (first capturing group)
alert( result.length ); // 2

result內容如下:
https://ithelp.ithome.com.tw/upload/images/20201007/20128122I4cwR2HkRC.jpg

  1. regexpg flag,會以陣列方式回傳所有匹配的字串結果
    (也就沒有capturing groups和其他的detail)
let str = "I love JavaScript";
let result = str.match(/Java(Script)/g);
alert( result[0] ); // JavaScript
alert( result.length ); // 1

result內容如下:
https://ithelp.ithome.com.tw/upload/images/20201007/20128122KBNkAQw8JV.jpg

  1. 沒有匹配到,會回傳null 回傳null 回傳null,不是空陣列

沒有注意到,容易產生以下的錯誤:

let str = "I love JavaScript";
let result = str.match(/HTML/);
alert(result); // null
alert(result.length); // Error: Cannot read property 'length' of null

如果希望result要是陣列,可以寫成:

let result = str.match(regexp) || [];

字串.search()

語法:str.search(regexp)

回傳第一個匹配到的位置,如果沒有符合的則回傳-1
(只會找第一個符合的!)

let str = "A drop of ink may make a million think";
alert( str.search( /ink/i ) ); // 10 (first match position)

字串.replace()

語法:str.replace(str|regexp,str|func)

最最最常見的用法,既能搜尋也能做到替換!

在不使用regexp做替換:

// replace a dash by a colon
alert('12-34-56'.replace("-", ":")) // 12:34-56

只有第一個-被做到替換,為了能替換掉所有-,可以用正規表示式/-/g

// replace all dashes by a colon
alert( '12-34-56'.replace( /-/g, ":" ) )  // 12:34:56

在先前Vowel CountWho likes it?有提到replace()基本用法
Create Phone Number則是提到replace()匹配群組的替換。


字串.split()

語法:str.split(regexp|substr,limit)

split()是分割字串用,可以用substr字串或是regexp當作分割或是分界。

// 用中線- 分割字串
alert('12-34-56'.split('-')) // array of [12,34,56]

// 用逗號和空白字元 分割字串
alert('12, 34, 56'.split(/,\s*/)) // array of [12,34,56]

以上內容及範例摘自:
Javascript.info-Methods of RegExp and String
MDN web docs-Regular expressions

以上為今日分享的內容,若有錯誤或是建議,請再隨時和我聯繫。


上一篇
Vasya - Clerk
下一篇
Valid Parentheses
系列文
菜鳥工程師的奇幻漂流:跟著kata活化手指和意識30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言