2014年8月8日 星期五

Regular Expression入門

前言

  • Regular expression一般翻譯做「正規表達式」之類的,但其實翻譯不重要,因為看了翻譯還是不知道他的用途。
  • 在字串裡搜尋字串是大家很常用的功能,例如在硬碟內找某個檔案,或者是在文章內找某個字。
  • 但更常用的是搜尋「某個pattern」,例如想要找「連續7個數字」或是「三個字母接一個特殊字元,後面又有1或2個數字」,就需要用到regular expression!
  • 很多程式語言(或者script)都會有regular expression,使用上大同小異,花點時間學習這些火星文,一生受用無窮。
  • 以下以autohotkey環境來講解,其實大部分也是翻譯自autohotkey的官方文件
  • 測試regular expression的工具

RegExMatch

  • 在開頭先簡介autohotkey內所用的函數RegExMatch,用法是
FoundPos := RegExMatch(Haystack, NeedleRegEx [, UnquotedOutputVar = "", StartingPosition = 1])
    • 一定要有的參數:Haystack是被搜尋的文字,Needle則是所搜尋的pattern,也就是底下要學的東西。
    • 選擇性參數:match後的結果會儲存在OutputVar變數裡,StartingPosition可以指定從Haystack的第幾個字元開始搜尋。
    • 這個函數會傳回第一個找到pattern的字元位置,如果沒找到的話是 0 。
    • 相較於autohotkey很多函數/變數是大小寫不區分,regular expression預設是區分大小寫的。

Regular Expression

  • 一般字元
    • 大部分的字元都可以直接用在regular expression內,搜尋起來就是和傳統的搜尋文字一樣,例如 RegExMatch("abcde","bcd") 會傳回 2 。
  • 特殊字元
    • 在regular expression裡有特殊意義,要用 \ 去escape,才會是原本的字元:\ . * ? + [ { | ( ) ^ $ 
    • 例如要找中括號,不能用 RegExMatch("()[]{}","[") ,而是要用 RegExMatch("()[]{}","\[") 
  • Symbols
    • .:一個點表示除了斷行以外的任何一個字元。
    • \d:表示任何一個數字,也就是0到9。如果要表達「一個非數字」,則用\D (大寫)。
    • \w:表示任何一個文字,包括數字、大小寫的a到z,還有底線 _ 。如果要表達「一個非文字」,則用\W (大寫)。
    • \s:表示某種空白字元,包括空白、tab (\t),斷行 (\r\n)等。如果要表達「一個非空白」,則用\S (大寫)。
    • [...]:一對中括號內為候選字,正面表列
      • [abc]:找某一個字元,可以是a,也可以是b或是c。
      • [a-z]:找某一個字元,可以是a到z。同理可以用在[A-Z][0-9],或是組合用[b-s4-7]
      • 候選字中某些特殊字元可以不用escape,例如 * ? + 都不用加 \ ,當然如果怕搞混加上去也沒關係。
      • [^...]:最前面標一個^表示是黑名單,找一個字元且這個字元不在黑名單中。
  • 數量詞
    • 前面的Symbol都是指單一字元,數量詞一定接在某個symbol右邊,也就是說數量詞作用在左邊那一個symbol。
    • *:表示0個或是0個以上。
    • ?:表示0個或是1個。
    • +:表示1個或是1個以上。
    • {min,max}:表示min個以上、max個以下。例如a{2,3}表示連在一起的兩個或三個a。
  • Syntax
    • \b:表示一個「文字邊界」,例如 cat\b 不會match到 catfish ,因為cat是fish連在一起的。\B(大寫)則表示「非文字邊界」。
    • ^ $:把^放在整個pattern的最前面表示「開頭」,把$放在整個pattern的最後面表示「結尾」,例如 ^bcd abc$ 都無法match到 abcd
    • |:表是「或」,例如 (Sun|Mon|Tues|Wednes|Thurs|Fri|Satur)day 可以match到 SundayMonday 或 ... 或 Saturday
    • ( ):小括號一方面可以讓pattern比較容易閱讀,一方面被括起來的部分會成為一個submatch。
  • Options
    • 在pattern的左邊,以一個右括號)隔開option和pattern,各個options可以連起來寫,或是用空白、tab分開。
    • i:表示case insensitive,例如 i)abc 可以match到 ABC
    • m:表示multiline模式,影響的是^$,在多行文字時本來表示「全部文字」的頭尾,會變成「一行文字」的頭尾。
    • s:讓一個點.表示「所有」字元,包括斷行。
    • U:ungreedy
      • 預設情況下如果是不定數量的數量詞* + ? { },regular expression會符合「盡量多」的字元,所以 1\d+1 會match到全部的 1000010000101,稱作greedy
      • 如果在數量詞後加一個問號?,則變成ungreedy1\d+?1 只會match到 100001。
      • 如果有U設定,則預設為ungreedy,加問號變greedy。
  • Submatch (subpattern)
    • 剛才提到小括號可以形成submatch,例如 RegExMatch("zzabcdefzz","ab(.*)e(f)",match) match變數會儲存 abcdefmatch1變數會儲存 cdmatch2變數會儲存 f
    • 如果小括號只是為了語法,而不是為了submatch,可以用(?:  )表示這個括號不是submatch,例如 RegExMatch("zzabcdefzz","ab(?:.*)e(f)",match) match變數會儲存 abcdefmatch1變數會儲存 f
    • (<?P<...>   ):Named subpattern,例如 RegExMatch("20140102","(?P<Year>\d{4})(?P<Month>\d{2})(?P<Day>\d{2})",match) 執行後,match20140101,而matchYear變數是2014matchMonth變數是01matchDay變數是02
  • Assertion
    • 雖然是用小括號,但不是submatch也不包含在match裡,僅僅是當成一個條件。
    • (?=   ):positive look ahead,例如 a(?=b) 會match一個a,這個a要接著b。
    • (?!   ):negative look ahead,例如 a(?!b) 會match一個a,這個a後面不能接著b。
    • (?<=  ):positive look behind,例如 (?<=a)b 會match一個b,這b左邊接著a。
    • (?<!  ):negative look behind,例如 (?<!a)b 會match一個b,這b左邊不能接著a。

Further Reading

2014年7月9日 星期三

自己寫武功祕笈:Radiologist的第一個Autohotkey

開發環境

主程式

  • 官方版autohotkey
  • Autohotkey_L:根據官方版加入更多功能,例如unicode支援、64位元支援、物件導向,而且有提供簡體中文的說明檔
  • 以上都有提供portable版本,免安裝,解壓縮後就可以直接用

Script File

  •  只有主程式沒用,還需要script才能做事,script的副檔名是ahk,但本質上就是文字檔,可以用任何文字編輯軟體打開撰打
  • 同樣是文字檔會有不同的編碼方式,原PO儲存時都使用UTF-8 (with BOM),對於中文字或是其實特殊文字比較不會變亂碼

編輯器

  • 工欲善其事,必先利其器,好的編輯器可以讓寫程式更有效率,包括偵測錯誤、函數提示、顏色標示
  • 原PO使用的是SciTE4Autohotkey,一樣有分安裝版和portable版

寫程式

前言

  • 所有程式都能做很簡單或是很複雜的事,autohotkey也是,尤其autohotkey特別針對日常使用電腦需要用到的功能,寫起來非常有效率,用最少的程式碼做最多的事
  • 本篇主要介紹血汗國家(地區?)的放射科醫師,靠著autohotkey在夾縫中求生存的一段故事

模擬鍵盤、滑鼠

  • 基本上打報告的所有動作,包括鍵盤上任何按鍵、滑鼠上任何按鍵和動作,都是可以模擬出來的,所以寫程式的第一步是思考、設計,「我要我的程式做什麼事情」,而且要step by step,分析每一個步驟
send
  • 官方詳細說明
  • 送出一個按鍵,例如:send blabla
  • 英文字母、數字、特殊符號可以直接送出,例如:send abc123&*?
    • 例外的是 ` ,要在字元前加一個`,也就是 send ``
    • ! # + ^ { } ,這些字元有特殊用途,要用大括號包圍起來,表示送出原本的字元而不是特殊用途,例如 send {!}{#}
  • 功能鍵(會自動和右邊一個按鍵變組合鍵)
    •  ^ 表示ctrl,例如 send ^c 就是按 ctrl + c
    •  ! 表示alt,例如 send !{F4} 就是按 alt + F4
    •  + 表示shift,例如 send ^+{esc} 就是按 ctrl + shift + esc
    •  # 表示視窗鍵(ctrl和alt中間那個),例如 send #e 就是按 win + e
  • 特殊字元
    • { } 包圍起來,族繁不及備載,可參考說明檔,大部分都很直覺,常用如下
    • {enter} {space} {tab}
    • {backspace} 或 {bs}、{delete} 或 {del}
    • {up} {down} {left} {right} {home} {end} {pgup} {pgdn}
    • {F1} ~ {F12}
    • 在數字盤的按鍵都是這個形式:{Numpad___}
  • 滑鼠按鍵
    • {LButton} {RButton} {MButton}
    • {WheelUp} {WheelDown}:滾輪
  • 重複同一個按鍵:send {space 10}會送出10個空白鍵

Hotstring & Hotkey & Settings


::cct::CT of the chest without and with contrast enhancement is read and compared with prior study dated . This CT study shows:{left 22}
  •  送出了這段文字,通常會將游標移到前面填入日期,所以在後面加上{left 22},將游標往左移動22次
  •  或者可以用^{left 5},因為 ctrl + left 會往左移動一個「字」而不是「字元」,但使用後的效果不如前一個方法精準
SendMode Input
  • 將send mode改成input模式,比較不會發生打報告打太快時,autohotkey送出的模擬按鍵和自己實際按的按鍵交錯送出
^!x::suspend
  • 打報告時還是常需要google查資料(&上facebook?),這時可以用suspend指令將這個script的所有hotstring和hotkey停用,繼續打報告時再按同一個快速鍵(也只有這個快速鍵不會被停用)回復
^!r::reload
  • 如果script在執行中,修改程式碼後要重新執行,可以直接用reload指令
^!e::
inputbox,addahk
if addahk!=
    fileappend,% addahk,% A_ScriptFullPath
reload
return

  • 跳出一個輸入框,輸入的文字(例如新的hotstring)會加到原本的script最底下,然後reload整個script,就能使用剛加入的hotstring
^!q::exitapp
  • exitapp指令可以離開整個script
~+enter::
~+NumpadEnter::
send -{space}

return
  •  bullet是項目符號,每個人用的都不一樣,原PO是用「- 」,設定快速鍵後按 ctrl + enter 可以跳到下一行並輸出項目符號

Dynamic Hotstring

  • 進階版的hotstring,見AHK論壇
  • 原始的hotstring是一對一的關係,打出一些特定的字跳出一些特定的字,dynamic  hotstring則是多對多的,打出某些pattern的字跳出某些pattern的字
  • 常見在一些列舉項目,例如left/right/bilateral、head/neck/chest/abdomen/pelvis,或是需要輸入某些數字,例如SE3 IM20,都適合用dynamic hotstring,舉一個例子…
#include hotstring.ahk

hotstring("([.\W])?(\d+)\.\.(\d+)(\W)","specifyImage",3)
return

specifyImage:
if $.value(1)="."
    send % "(SE" $.value(2) " IM" $.value(3) ")" $.value(4)
else
    send % $.value(1) "SE" $.value(2) " IM" $.value(3) $.value(4)
return

  • 下載Hotstring.ahk後放到自己的script的資料夾;自己的script(通常在最前面)要有一行#include hotstring.ahk載入函數
  • hotstring("([.\W])?(\d+)..(\d+)(\W)","specifyImage",3)要放在「第一個return」之前,因為return之後的程式碼不會被直接執行
    • ([.\W])?(\d+)..(\d+)(\W)表示要trigger的pattern
    • specifyImage表示trigger後要執行的段落標籤
    • 3表示pattern是用regular expression
  • 總之最後的效果是
    • 輸入 .3..20 ,輸出 (SE3 IM20) 
    • 輸入 3..20 ,輸出 SE3 IM20 

    2013年11月23日 星期六

    Hotstring Helper

     Tool for Radiology Resident !!

    Background

    • 當resident開始用起VS們的ahk...
      • 看shoulder plain film,一直要打down-sloping and low-lying of the acromion真是累
      • 打開游醫師的cwy.ahk,搜尋看看有沒有對應的hotstring
      • 找到了!以後只要打「shd」就會是down-sloping and low-lying of the acromion
      • 這樣實在太浪費時間了!!

    Hotstring Helper使用說明

    • 把要查詢的ahk(可以多個)全部複製到Hotstring Helper.exe的資料夾 
    • 執行Hotstring Helper.exe
    • 開啟RIS (目前限制在RIS裡才查詢)
    • 打報告打一半想查某個字(eg. acromion)相關的hotstring,則打「;acromion」,也就是一個分號,再接著查詢的單字
    • 如上圖只要當作注音輸入法使用,輸入0~9後就會把剛才的「;acromion」取代成候選句
      • 輸入0是第10個候選句,不是第一個!
    • 其他小技巧及注意事項
      • 如果按空白鍵則自動選擇第一個候選句
      • 至少輸入三個字母以上才會查詢,就上面的例子至少要輸入「;acr」才會出現選單
      • 如果有一頁以上的結果,可用滑鼠滾輪捲動
      • 只要輸入字母以外的按鍵(eg. ESC),或是滑鼠按鍵,就會停止查詢,選單消失
        •  問號(?)和星號(*)為例外,問號表示「任一字元」,星號表示「零或多個字元」
        • 例如「gr?y」會搜尋grey或gray
      • 或者可以先key一串字(片語、句子),選取後按Alt+F搜尋



    2013年6月9日 星期日

    Facebook備份

    話說前幾天試用Facebook備份,其實不用從email收確認信,從facebook備份頁再輸入一次密碼就能下載了。但下載下來覺得裡面像渣一樣…

    • 總體來說,檔名一堆亂碼,非英文數字的字元整個是悲劇,例如 ??瘞湔?蝞?Photos 或是 蝚砌??蝵居 根本不知道是尛。
    • 下載下來是一個zip檔,裡面先是一個資料夾,名稱是自己的facebook首頁連結去掉facebook網域,例如我的是scsnake.chen。解壓縮後點開index.html就可以看到備份的成果,以下就zip檔內的資料夾、檔案簡介…
    • html
      • album開頭的一些html檔
        • 各個facebook相簿摘要,該是縮圖的部分都不會有圖,只剩下文字資訊(例如照片底下的好友回應)。
      • events.html
        • 加入過的活動,檔題還保有超連結,算是資訊比較完整的。
      • friends.html
        • 好友清單,內容走極簡風,就只是純文字的好友列表。
      • message.html
        • 跟所有人的訊息都收集在同一頁裡,以對話者分類,所以除了第一個人外都要用搜尋名字才知道在網頁中哪個範圍。
        • 最上面是最早的日期,但也只到2012年9月,往下到備份的時間點。
      • notes.html
        • 網誌內容加回應,一樣是純文字版,有超連結的文字會留著。
      • profiles.html
        • 個資大全
      • video.html
        • 分享過的影片,很意外地可以直接點影片收看,最令人滿意的備份。
    • photo
      • 只是自己的大頭照一張。
    • photos
      • 相簿、照片應該是完整的,除了檔名幾乎滅團,以及因為亂碼的因素無法從壓縮檔中解壓縮出來。
    • videos
      • 上傳到facebook的影片檔。

    因為想要備份完整的訊息,只好出動土法煉鋼:
    • 先到facebook的收件匣
    • 持續的讓滑鼠往上滾,先前的訊息會一點一滴地讀取進來
      • Autohotkey/按鍵精靈是我們的好朋友,10000則訊息其實不用1小時就捲到頂了。
      • 請選擇比較穩的瀏覽器例如Chrome,因為10000則訊息會用到快900MB多的記憶體。
    • 全部loading完別想全選+複製,就算是Chrome還是當掉了…
      • 在IE或Chrome按F12會出現主控台,IE點「指令碼」/ Chrome點「Console」,輸入  document.getElementById('webMessengerRecentMessages').innerText ,會出現純文字版的所有訊息,複製之。
    • 10000則訊息大約400KB,大家每天洩露給facebook或google的資訊其實檔案不大,儲存起來完全不費功夫呀!

    2013年5月25日 星期六

    怪談 *2


    身為二線科醫師,可能離開臨床太久,少見多怪,以下純粹客觀陳述,希望不要被告 orz


    • 某整型外科陳姓大P,專長為hemangioma,Google可以查到很多讚揚他的blog,不過在放射科的角度,他開的檢查單一直讓我們很頭痛...
      • 很小很迷你很distal的hemangioma,而且病人常常是小孩子,還是會order CT用力電下去
      • 做完CT一定要求完美的3D重組,如果3D重組不漂亮,會要求重做一次CT(是的,只為了3D不漂亮這個理由),再把病人電一次。(我遇到的那一次,被我勸退)
      • 3D重組要包括opacified的血管及半透明若隱若現的bone當背景,除了要看起來漂亮,還要求要跟之前的3D重組顏色相同、透明度相同,不然他們(因為都是CR打電話來)會「沒辦法開刀」。(一樣,我也是拒絕這樣的要求)

    • 昨天在閱片考試時學姐接到電話,說開刀房的病人心臟破掉,要急做CT ?!!!!!!!!
      • 都已經在開刀房了,來CT再回去不是路途遙遠嗎...
      • 大家在猜,應該是有信心把病人救活,所以做個術前CT,術後再做CT,以便發篇 _____ ,畢竟台大醫院是台灣的 __ 術首府嘛~~~
      • 話說,病人在CT room叫9595,只有放射科要寫異常事件通報,這整個是不合邏輯!例如最近一次9595,急診重症病人才剛移床到CT就CPR,但急診醫師覺得不意外,本來就準備要CPR了...