iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 19
0
自我挑戰組

菜鳥工程師的奇幻漂流:跟著kata活化手指和意識系列 第 19

Complementary DNA

今日kata

原始題目如下:(7kyu)
Deoxyribonucleic acid (DNA) is a chemical found in the nucleus of cells and carries the "instructions" for the development and functioning of living organisms.
In DNA strings, symbols "A" and "T" are complements of each other, as "C" and "G". You have function with one side of the DNA (string, except for Haskell); you need to get the other complementary side. DNA strand is never empty or there is no DNA at all (again, except for Haskell).

翻譯:
簡單來說....找出DNA配對的序列(含氮鹼基),A與T配對,C與G配對。

範例:

DNAStrand ("ATTGC") // return "TAACG"
DNAStrand ("GTAT") // return "CATA" 

構想&解法

function DNAStrand(dna) {
  return dna.replace(/[AT]/g, function(val) {
    return val === 'A' ? 'T' : 'A'
  }).replace(/[CG]/g, function(val) {
    return val === 'C' ? 'G' : 'C'
  })
}

硬是把會的RegExp派上用場...
分兩組分別尋找A or TC or G,看匹配的是什麼就取代對應的含氮鹼基。


其他解法觀摩

function DNAStrand(dna) {
  return dna.replace(/./g, function(c) {
    return DNAStrand.pairs[c]
  })
}

DNAStrand.pairs = {
  A: 'T',
  T: 'A',
  C: 'G',
  G: 'C',
}

.任意字元....原來可以這樣用,使用物件Object決定要回傳哪個對應的序列,之後要改規則也很方便!


整理

RegExp正規表示式

截至目前,正規表示式無所不在,凡是有關字串搜尋、字串替換、驗證格式,使用正規表示式幾乎通通有解。

Regular Expression,稱正規表示式﹑正規表示法。使用一套符號來描述符合某個規則或某個模式的字串。在Javascript中,正規表示式是內建的物件:

re = new RegExp("pattern", "flag")

pattern為正規表示法,flag為比對的方式

  • g: 全域比對(global match)
    • 正規表示法預設找到第一個符合的結果就結束了
  • i: 忽略大小寫 (ignore case)
  • gi:全域比對且忽略大小寫

初次擦身而過

遙想第一次聽到這個詞,是剛學完if for loop switch case 要寫身分證格式驗證的作業時,老師補充一句可以試試看使用正規表示式當時沒放在心上 只想用剛學到的語法完成作業

簡略說明規則,身分證號碼一共有10碼,為英文字母(戶籍地代號)+9碼數字

  • 每個英文字母有對應的數字
  • 第2碼為性別 (1:男;2:女生)
  • 扣除最後一碼檢查碼,由右至左數字依序乘上1~9並相加
  • 10-(相加結果/10的餘數)必須等於檢查碼
// A    1 2 3 4 5 6 7 8  9
// 1 0  1 2 3 4 5 6 7 8 檢查
// X
// 1 9  8 7 6 5 4 3 2 1 
// 1+0+8+14+18+20+20+18+14+8=121 
// 121%10=1
// 10-1=9 等於檢查碼,該身分證格式正確

先附上三年前的原汁原味code:

function isIdNo (){
	 var input = document.getElementById("number").value;
	 var number=input.toUpperCase();
	 var check=0;
	 var first=number.charAt(0);
	 var gender=number.charAt(1);
	
 	// 判斷總長度是否為10碼
 	if ((number.length)!=10) {
 		alert("是不是有打錯??");
 		return;
 	}
 	
 	// 將第一碼英文轉為數字,若第一碼不為英文 顯示提示
 		switch (first){
		case 'A':
		var newnumber = number.replace("A","10")
		break;
		case 'B':
		var newnumber = number.replace("B","11")
		break;
		case 'C':
		var newnumber = number.replace("C","12")
		break;
		case 'D':
		var newnumber = number.replace("D","13")
		break;		
		case 'E':
		var newnumber = number.replace("E","14")
		break;	
		case 'F':
		var newnumber = number.replace("F","15")
		break;
		case 'G':
		var newnumber = number.replace("G","16")
		break;	
		case 'H':
		var newnumber = number.replace("H","17")
		break;	
		case 'I':
		var newnumber = number.replace("I","34")
		break;	
		case 'J':
		var newnumber = number.replace("J","18")
		break;	
		case 'K':
		var newnumber = number.replace("K","19")
		break;	
		case 'L':
		var newnumber = number.replace("L","20")
		break;	
		case 'M':
		var newnumber = number.replace("M","21")
		break;
		case 'N':
		var newnumber = number.replace("N","22")
		break;
		case 'O':
		var newnumber = number.replace("O","35")
		break;	
		case 'P':
		var newnumber = number.replace("P","23")
		break;		
		case 'Q':
		var newnumber = number.replace("Q","23")
		break;
		case 'R':
		var newnumber = number.replace("R","25")
		break;	
		case 'S':
		var newnumber = number.replace("S","26")
		break;	
		case 'T':
		var newnumber = number.replace("T","27")
		break;	
		case 'U':
		var newnumber = number.replace("U","28")
		break;
		case 'V':
		var newnumber = number.replace("V","29")
		break;	
		case 'W':
		var newnumber = number.replace("W","32")
		break;	
		case 'X':
		var newnumber = number.replace("X","30")
		break;	
		case 'Y':
		var newnumber = number.replace("Y","31")
		break;	
		case 'Z':
		var newnumber = number.replace("Z","33")
		break;
		default:
		 alert("首碼要A~Z唷");		
	 }
     // 判斷第二碼-性別碼是否正確
	if (gender != "1"  &&  gender !="2" ){
 		alert("第二碼怪怪的");
 	}

 	// 計算檢查碼 i為1~9 j為9~1
 	// ex:輸入身分證之第10碼(位置9)*1
 	// ~~~~輸入身分證之第2碼(位置1)*9
	for( i=1; i<10;i++){	
		for (j=9; j>0; j--){		
			check+=newnumber.charAt(j)*i;
			i++;
		}
	}

	// 再加上第1碼(位置0)*1
	check+=newnumber.charAt(0)*1;
	
    // 取餘數
	var remainder=(check%10);

	// 檢查碼=10減去餘數
	var code= 10-remainder;

	// 若餘數為0 檢查碼為0
	if (remainder==10){
        code=0;
	}
    
	// 比對計算的檢查碼和輸入的是否一致
	if(code != number.charAt(9)){
        alert("號碼有輸錯唷~~~~");
	}else{
        alert("正確無誤");
	}
}

alert真是初學者的好朋友...

其實有很多地方可以優化像是:

  • Mapping英文字母的部分觀察規則,存入陣列中

    • ['A', 'B', 'C', 'D',
      'E', 'F', 'G', 'H', 'J', 'K', 'L', 'M',
      'N', 'P', 'Q', 'R', 'S', 'T', 'U', 'V',
      'X', 'Y', 'W', 'Z', 'I', 'O']
    • 該字母順序對應數字依序是10~35
  • 在進行運算前,可以先利用正規表示法驗證基本格式

    • regExp=/^[a-z](1|2)\d{8}$/i;
    • 就可以省略一個一個用if判斷長度、判斷第一碼和第二碼為何。

參考自:使用JavaScript驗證身份證號碼及其原理

期待之後有篇幅來好好整理正規表示式~/images/emoticon/emoticon02.gif

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


上一篇
The Supermarket Queue
下一篇
Valid Braces
系列文
菜鳥工程師的奇幻漂流:跟著kata活化手指和意識30

尚未有邦友留言

立即登入留言