研發宅的腦漿
演算法時期->設計模式時期->軟體工程時期,這是我的宅宅路
2016年1月27日 星期三
RSA, AES加密大檔案
如果改用AES則沒有長度限制,但AES是對稱式的加密,等於你要把密鑰傳給對方,對方才能解密。這樣子中間轉手的Router,或是同網域中的電腦就能接收到到你的密鑰了。
那麼解決方法是什麼呢?
答:將資料用AES加密,AES加密時的密鑰用RSA加密,然後一起傳給對方就行了
那怎麼實作呢?Linux上面有openssl所有的功能都在裡面了,不管是要編碼,要加密解密,通通都有了
2015年3月12日 星期四
Github Pages 使用jekyll安裝與設定,及連結多個github專案
第一個github pages
在github建立一個repository 名稱為<username>.github.io
好了,剛建立好等一陣子,打開瀏覽器進入<username>.github.io
,就可以看到空白網站了
把<username>.github.io
git clone下來,隨便加個index.html
就可以看到結果了
連結其他的github專案
每個github專案都可以自己管理自己的github pages,不用都放在剛剛那個<username>.github.io
裡面。
譬如你還有一個github專案,名稱為project
,則在project
裡面再開啟一條branch命名為gh-pages
,那麼連結<username>.github.io/project
,就可以連到project
裡面了。
只是gh-pages
這條分支,都只會用來做專案的網頁呈現,所以我們會將它設定為獨立分支,不從master裡面分出來,所以開啟分支時,使用
git checkout --orphan gh-pages
就可以開啟獨立的分支,沒有任何parent的分支,這時候再把原本的檔案都刪掉,這條分支就專心做網頁就好。
使用jekyll
從HTML慢慢刻出一個網頁有點累,github pages大多是用jekyll這個框架來產生部落格網站。
怎麼安裝,jekyll-quick-start 已經講得很清楚了,這邊說一下,連結其他github專案時要特別設定的地方
在jekyll根目錄有個_config.yml
檔案,找到BASE_PATH :
這一行。如果沒有修改的話,在網頁裡面預設的連結都會連回<username>.github.io
,而不是你目前的<username>.github.io/project
,這裡使用絕對路徑或相對路徑都可以
絕對路徑
BASE_PATH : <username>.github.io/project
相對路徑
BASE_PATH : /project
這樣子預設的連結就不會亂跑了,我一開始找不到,只好傻傻的去改模板,越改越覺得不對勁,不可能要使用者用這麼智障的方法,仔細再看一次_config.yml
檔,才發現可以設定
2014年12月12日 星期五
linux, bash, find 的應用(-exec, sed -i, 檔案內取代, 與xargs比較)
find -exec
find -exec
指的是將找到的檔案,送到後面的指令去處理。從-exec
到\;
為止,代表是接受從find送來要處理的指令,而送來的檔案將用{}
代表找到的檔案。
譬如你想把所有副檔名為.log
的檔案刪除掉,可以這麼做
find . -type f -name "*.log" -exec rm {} \;
(其實我加上-type f
有點多餘,因為我已經指定-name "*.log"
了,就不可能輸出資料夾了。)
如果刪檔案的時候,一直要你按yes
,可以這樣
yes | find . -type f -name "*.log" -exec rm {} \;
yes
這個指令會一直串流輸出yes,這樣刪檔案就自動一直輸入yes
例子中find
找到的檔案,就放到-exec
至\;
之間的指令去處理,譬如找到了檔案develop.log
,就會變成
rm develop.log
另外,{}
並不是規定只能出現一次,譬如你要將資料夾內所有檔案加上副檔名log
,可以這麼做
find . -type f -exec mv {} {}.log \;
這指令會包含子資料前內的檔案都加上.log副檔名。如果只想要目前資料夾的檔案,所以可以加上-maxdepth 1
,若要地回到下一層資料夾可以將1改成2,3或4以此類推
find . -maxdepth 1 -type f -exec mv {} {}.log \;
因此,若要批次改變檔案的內容,就可以搭配find -exec
跟sed -i
。sed 加上 -i 參數,代表直接對檔案內容做修改。
我常常在幫別人複製或移動網站,很多人的網址都寫成包含域名的絕對路徑,所以常常要用這個指令去找出所有含舊域名的檔案,並改成新域名。
譬如舊域名為http://www.old.com
,要改成http://www.new.com
,我會這麼做
find . -type f -exec sed -i 's/www.old.com/www.new.com/g' {} \;
(sed這個指令在OS X上面如果照上例那樣執行,會有錯誤訊息。詳細請參考stackoverflow上面的討論)
這樣子會找遍所有的檔案,需要的時間有點久。我會再加上參數-not -name "不需要的檔名"
,來排除一些不需要尋找的檔案
find . -type f -not -name "*.log" -not -name "*.jpg" -exec sed -i 's/www.old.com/www.new.com/g' {} \;
像這樣跳過所有的log檔與jpg圖檔,有需要可以加上其他如-not -name "*.png"
,才加快速度。或者乾脆指定-name "*html"
或-name "*.php"
,只尋找相關網頁檔。
xargs
xargs
使用起來就沒有像find -exec
可以將檔名以{}
的形式傳給指令去安排。xargs只能收管線資料當成指令參數來執行。
雖然使用上沒有靈活,但管線指令就是他的優點,所以他不只可以搭配find指令,echo
資料給他也可以,譬如
echo a b c d e | xargs touch
一次創造了a b c d e五個檔案。如果find後面不用-exec,可以改用管線指令傳給xargs,譬如本篇第一個刪除檔案的例子,改用xargs變成
find -name "*.log" | xargs rm
但是後面改檔名的例子,就沒辦法這麼簡單的處理(可以處理,但改用xargs還要搭配其他指令,本篇已經太長,不再節外生枝介紹)
另外像改檔案內容的指令,因為檔名參數接在最後面,所以也可以很簡單的改用xargs來處理
find . -type f | xargs sed -i 's/www.old.com/www.new.com/g'
因此,當我用find在處理檔案時,我會用find -exec
比較靈活。其他情況下我就用管線串流到xargs
來處理
2014年12月9日 星期二
HTML, CSS, 相對視窗或螢幕的高度與寬度
在w3school.com網站,CSS Units有各種與寬度的表示法
以我使用的頻率來排序:
- px: 使用螢幕幾個像素(但是還要考慮Retina螢幕像素是一般螢幕像素的兩倍)
- %: 相對父層的大小比例
- vh, vw: 相對於瀏覽器展示網頁區域的大小(不是整個瀏覽器的大小,沒包含瀏覽器的工具列,只有展示網頁的區域)
- vmin: vh, vw取最小值(另外還有vmax則是取最大值,但是目前IE跟safari不支援)
px
與%
很常用,vh
,vw
與vmin
是CSS3的新產物,表示相對瀏覽器展示頁面的大小
相對視窗大小
這邊先說明,vh
,vw
與vmin
只包含網頁顯示區域的長寬,不包含瀏覽器的工具列
先從dom的最根本講起好了,一份HTML文件,根是<html></html>
(雖然沒有嚴格規定,不寫也能顯示),然後這個根的父元件就是瀏覽器的網頁頁面顯示區
因此,如果對<html></html>
宣告大小是100%
就跟宣告100vh
一樣,因為都是指瀏覽器的網頁頁面顯示區大小
這個範例是將html設定為100vh
<html style="height: 100vh">
<head>
<script src="https://code.jquery.com/jquery-1.11.1.min.js"></script>
<script type="text/javascript">
console.log($('html').height());
</script>
</head>
</html>
這個範例是將html設定為100%
<html style="height: 100%">
<head>
<script src="https://code.jquery.com/jquery-1.11.1.min.js"></script>
<script type="text/javascript">
console.log($('html').height());
</script>
</head>
</html>
這兩者在瀏覽器的console應該輸出一樣的大小
如果從html, body到div , 這些tag都填入100%,則從頭到尾都填滿整個視窗(當然還注意body預設有padding, margin佔有一些寬度,要把他們都設為0,才會真的佔滿全畫面)
不過現在有vh, vw,就不用這麼麻煩了,可以只設定長度為100vh, 寬度為100vw,就可以填滿整個畫面(依然得注意body預設佔有padding跟margin)
像下面這樣就能把兩個div排在一起,並且以瀏覽器寬度3:7的比例,分割成兩個區塊
<html>
<head></head>
<body style="margin: 0;padding: 0;">
<div style="width: 30vw;float:left;">Left...</div>
<div style="width: 70vw;float:left;">Right...</div>
</body>
</html>
還有一個問題,以往使用桌上型電腦的螢幕,我們可以預期大部分人的電腦,都是寬度大於長度,大部份的人也都是用全螢幕瀏覽網頁。所以我們很信任的將長寬都設定成vh
就可以變成正方形,並且不超過瀏覽器大小。
但是現在手機螢幕,可以拿直的,也可以拿橫的,那要怎麼辦呢?就使用vmin
吧
譬如我們要顯示一張正方形的圖片,希望以最大張的方式呈現
<html>
<head></head>
<body style="margin: 0;padding: 0;">
<img src="圖片路徑" style="width: 100vmin;height: 100vmin;">
</body>
</html>
這樣就不怕桌機或手機,螢幕擺直得或橫的,都以最大張,且不會超出瀏覽器範圍欄顯示圖片
相對螢幕大小
那可不可以相對於使用者整個螢幕的大小?
可以,但是要使用Javascript去設定,在Javascript裡面直接使用screen.height
與screen.width
,就可以取得螢幕大小(關於screen
是什麼?請參考w3school的相關頁面)
之後再用dom語法,去改你要改的地方,假設你要將所有的div tag寬度都隨使用者螢幕寬度改變,這邊使用jQuery:
$('div').width(screen.width);
這時候不管使用者怎麼拉動瀏覽器的寬度,所有的div tag寬度都等是螢幕寬度
如果想單純使用javascipt的話,語法比較冗長一點,可以參考w3chool的頁面,注意他傳入的參數後面還要接單位,所以在screen.width
之後記得再加上"px"
,之後才當引數傳進去
回到原本的jQuery版本,如果想要75%的螢幕大小
$('div').width(screen.width * 0.75);
想要30%的螢幕大小
$('div').width(screen.width * 0.3);
以此類推,我一開始會害怕對screen.width做數學運算,因為不確定內容是字串還是數字。但是多慮了,javascript可以對數字做數學運算,也可以對內容是數字的字串做數學運算
'10' * '10' // 輸出100
'10' * 10 // 也輸出100
如果是在Ruby,則是輸出"10101010101010101010"
,所以在javascript裡面,不用怕,他內容是數字,就直接對他做數學運算,不用先檢查型別。(若字串內容不是數字,會輸出NaN
,Not a Number的意思)
2014年12月4日 星期四
Linux, bash, 壓縮, tar, bz2, xz, 7z, 壓縮率
Linux, bash, 壓縮, tar, bz2, xz, 7z, 壓縮率
如果只是想查各種副檔名的解壓縮指令,只要Google副檔名就可以找到(例如:tar.bz2)
這邊主要是在對資料夾壓縮時,為了自訂壓縮率而深入研究壓縮指令而產生。
tar 可以對檔案或資料夾進行單存的打包(或解開打包),後面接c代表打包,x代表解開打包。這邊在Bash底下產生一個簡單的文字檔來練習:
echo "Hello World" > text
tar c text
# 輸出 text000644 000765 000000 00000000014 12437746653 012241 0ustar00wemeewheel000000 000000 Hello World
# 如果要儲存,加上參數f,並指定存檔名稱
tar cf text1.tar text
# 或者使用串流來寫入檔案也可以(實際應用不建議)
tar c text > text2.tar
原始檔案12B, 打包後2K, 使用串流寫入的10K, 可以確定打包完全不會有壓縮的效果
12B 12 4 10:57 text
2.0K 12 4 11:01 text1.tar
10K 12 4 11:01 text2.tar
其實打包主要目的在於,我常用的bz2壓縮,只能對檔案壓縮,不能對目錄壓縮,所以才需要先把目錄打包成一個檔案,再用bz2去壓縮它
接下來,弄個目錄跟文字檔來測試
mkdir dir
echo "Hello World" > dir/text
tar cf dir1.tar dir
tar c dir > dir2.tar
結果一樣,使用串流寫入的,佔的容量比較大
102B 12 4 11:28 dir
2.5K 12 4 11:44 dir1.tar
10K 12 4 11:44 dir2.tar
接下來,使用bz2壓縮看看
bzip2 -z dir1.tar
bzip2 -z dir2.tar
來看看所佔用的容量
102B 12 4 11:28 dir
167B 12 4 11:44 dir1.tar.bz2
169B 12 4 11:44 dir2.tar.bz2
壓縮過後都變小了,分成先打包,再用bz2壓縮,其實是因為tar指令只是打包,頂多只能加上參數j,表示打包過程使用bz2,(或參數z,表示打包過程使用gz),無法指定壓縮比
# 將目錄打包之後,再用bz2壓縮並指定壓縮比
bzip2 -9 -z dir1.tar
如果要寫成一行的話,可以打包時,輸出到串流,在使用管線指令輸入到bzip2, 因為輸入是串流,bzip2無法指定要壓縮的檔案,所以把壓縮結果使用參數c,再一次輸出到串流,並儲存成檔案
tar c dir | bzip2 -c > dir.tar.bz2
# tar 無法指定壓縮比,在bzip2指定壓縮比
tar c dir | bzip2 -9 -c > dir.tar.bz2
同理,如果使用xz壓縮時,想一併指定壓縮比,也用同樣方式
tar c dir | xz -9 -c > dir.tar.xz
因為bz2壓縮,在Windows開啟中文檔名,常常變成亂碼,可以改用7zip來壓縮,如果使用7zip,他沒有辦法吃管線進來的資料,那怎麼辦?分兩行指令,先打包在壓縮嗎?
不用啦~ 7zip可以直接對目錄壓縮,直接壓縮,只是它指定壓縮比的參數是-mx數字
7za a -mx9 dir.7z dir
這樣子就直接對dir
這個目錄以最大壓縮的壓縮比去執行了
2014年12月3日 星期三
Ruby, dup跟clone的不同, 淺層複製與深層複製
Ruby, dup跟clone的不同, 淺層複製與深層複製
Ruby裡面,對於物件的複製有兩個方法,分別是對物件呼叫dup
跟clone
,這兩種有什麼不同呢?這兩種方法並非只是alias的名稱而已。
先不討論淺層複製跟深層複製的問題,先來看看呼叫dup做了什麼事情。假設有個class:
class Foo
def foo
'foo'
end
end
我們來試試看,產生Foo物件,然後對他呼叫dup
:
foo = Foo.new
dup_foo = foo.dup
dup_foo.foo # => 'foo'
一切依照預期,順利的進行複製了,接下來我們對foo動態增加一些Method上去,看看能不能夠複製(至於如何對物件動態增加Method請參考這篇)
class << foo
def run
'run'
end
end
foo.foo # => 'foo' 原本class就有宣告 沒問題
foo.run # => 'run' 動態新增的Method 也沒問題
dup_foo_2 = foo.dup
dup_foo_2.foo # => 'foo' 原本class就有宣告 沒問題
dup_foo_2.run # => 發生錯誤,No Method Error
由此,可以知道,dup方法,僅對完整宣告的class進行複製,動態增加的不會複製,那麼我們再多測試一點,使用另一種方法增加Method。我們把整個程式碼完整再寫過
class Foo
def foo
'foo'
end
end
foo = Foo.new
dup_foo = foo.dup
# 使用另一種方法增加Method到Foo上面去
class Foo
def go
'go'
end
end
foo.go # => 'go'
dup_foo.go # => 'go', 正常執行
由此可見,只要是宣告成所有class Foo可以使用的Methods都可以被dup
所複製,只有動態為單一Foo物件增加的Methods不能被dup
複製進去
那麼clone
方法,相對dup
方法,就是完整地複製出一模一樣的物件
class Bar
def bar
'bar'
end
end
bar = Bar.new
class << bar
def run
'run'
end
end
clone_bar = bar.clone
clone_bar.bar # => 'bar'
clone_bar.run # => 'run', 動態增加的方法也一併複製了
接下來,來探討一下淺層複製跟深層複製的問題,都只是淺層複製
ary = ['hello']
dup_ary = ary.dup
clone_ary = ary.clone
dup_ary[0][0] = 'X'
p ary # => ["Xello"], 原本的ary被改掉了
clone_ary[0][0] = 'Y'
p ary # => ["Yello"], 原本的ary也被改掉了
如果要進行深層複製,就得遞迴對陣列中每個物件,都進行複製。
在Ruby on Rails裡面,直接提供deep_dup
(但沒有提供deep_clone
)
如果是在傳統的Ruby,我們可以自己實作deep_dup方法,來進行深層複製,在stackoverflow上面,我找到一個不錯的寫法
# 寫得不錯,如果物件是Array, 就繼續遞迴
class Array
def deep_dup
map {|x| x.deep_dup}
end
end
# 直到不是Array,就進行複製,但這邊沒考慮到Ruby的容器還有Hash, Set ... 等,這些也需要做深層複製,所以這邊若遇到Hash, Set之類的容器就變成淺層複製了
class Object
def deep_dup
dup
end
end
# 這邊小心Numeric類別的物件,沒有dup方法,所以就直接回傳本身
class Numeric
def deep_dup
self
end
end
這個例子只有對Array類別進行深層複製,如果你有用到Hash, Set,甚至是你自己寫的容器,自己實做的iterator pattern ... 等,就得自行再加上deep_dup方法上去。
2014年12月2日 星期二
RUBY,大寫數字轉小寫數字,國字數字轉阿拉伯數字
RUBY,大寫數字轉小寫數字,國字數字轉阿拉伯數字
今天,我在處理中文地址的時候,發現有人的門牌號碼填國字,譬如中正路四三號
,也有人會填中正路43號
,當然沒人是填中正路肆參號
,反正程式邏輯是一樣的。(本方法忽略四十三
->43
這種格式,若有必要,請自行寫程式判定京兆億萬千百十
出現的位置,是否合理,然後再進行轉換)
一般想到的就是把字串裡面每個字遍尋一遍,然後寫個switch,對出現的字元進行轉換,譬如:
// psudo code
for each character in string
switch(character)
case: '一'
convert_to(1)
case: '二'
convert_to(2)
.
.
.
case: '九'
convert_to(9)
end
end
但其實你使用的是Ruby語言的話,其實Ruby語言有提供一個很簡潔的方法string.tr(from_str, to_str)
使用的方式是這樣子的,提供兩個字串,兩個字串相對應的位置會互相轉換,譬如提供兩個字串:
#輸入字串1
'abc'
#輸入字串2
'123'
則會將a變為1, b變為2, c變為3,舉個實際例子:
"xx_abc_xx".tr('abc', '123')
# 輸出 "xx_123_xx"
"xx_ccc_xx".tr('abc', '123')
# 輸出 "xx_333_xx", '1'跟'2'都沒出現?因為呼叫tr的字串裡面也沒有'a'跟'b'呀~
"cba".tr('abc', '123')
# 輸出 "321", 為什麼反過來?因為呼叫tr的字串是'cba'呀~(a變為1, b變為2, c變為3)
上面的例子,是比較快速簡易的應用,兩個輸入的字串長度一樣,對於呼叫tr方法的字串,就會將內容替換掉。那如果要傳入兩個字串不一樣長,譬如第一二個比較長,那多出來的部分則不會用到,譬如:
"abc".tr('ab', '123')
# 輸出"12c", 第二個引數中,那個'3'則不會用到
如果是第一個字串比較長,譬如:
"abc".tr('abc', '12')
# 輸出"122", 第一個引數比第二個引數的長度還要長,則第二個引數比較長沒得對應的部分,直接用第二個引數中,最後一個字元替換
#同理
"abcdefghijk".tr('abcdefg', '12')
# 輸出"1222222hijk"
所以我們將大小寫國字數字轉阿拉伯數字,可以全部用列舉的方舉出來,讓他們一一對應
chinese = "零一二三四五六七八九"
arabic = "0123456789"
"一三五七九".tr(chinese, arabic)
# 輸出 "13579"
# 反過來,也可以用阿拉伯數字轉國字
"98765".tr(arabic, chinese)
#輸出 "九八七六五"
#多個大寫數字
big_chinese = "零壹贰叁肆伍陆柒捌玖"
"壹贰叁肆伍".tr(big_chinese, chinese)
# 輸出"一二三四五"
但這邊有個簡易的寫法,參考Ruby的正規表示式(可以在這個網頁做測試)
輸入引入的部分,如果正規表示式中,使用中括號的用法,例如:
[abc] # 表示任何abc
[^abc] # 表示任何非abc,注意'^'符號放在中括號內,代表'非',而不是代表開頭字元
[1-9] # 表示任何1到9之間的字元
所以我們數字轉換的例子也可以寫成
chinese = "零一二三四五六七八九"
"一三五七九".tr(chinese, '0-9')
# 輸出 "13579"
就可以直接用'0-9'
代表所有的阿拉伯數字,那麼是否也可以用'零-九'
來代表所有的國字數字呢?
不行的,因為國字的排序並不像英文字元一樣的排法,你可以這樣測試看看
('零'..'九').each{|c| puts c}
# 沒有印出任何字元
('一'..'九').each{|c| puts c}
#印出 一 丁 丂 七 丄 丅 丆 ... 九
可見國字是用筆劃排序的,所以無法使用'零-九'
來代表數字,得一一列舉出來。
所以關於門牌號碼,就可以這樣子處理了,全部轉為阿拉伯數字
address = '中正路四三號'
chinese = "零一二三四五六七八九"
address.tr(chinese, '0-9')
輸出"中正路43號"
同理,也可以玩玩英文大小寫轉換
# 小寫轉大寫,一般寫法
'hello world'.upcase # => "HELLO WORLD"
# 使用tr, 多此一舉一下
'hello world'.tr('a-z', 'A-Z') # => "HELLO WORLD"