Chapter 10: Exercises

Part 1

  1. 設計一個函數 captalize.m,其用法如下:
    outputStr = capalize(inputStr)
    其中 inputStr 是一個輸入英文字串,函數 captalize 會將此字串中,每個字(Word)的第一個字母改成大寫,其餘則為小寫,並將多個空格代換成一個空格,outputStr 則是最後的輸出字串。例如,當輸入是 'you are My sunshine' 時,所得到的輸出字串是 'You Are My Sunshine'。

    Hint
    可使用 upper 和 lower 指令。

    10-字元與字串/captalize.mfunction out = capalize(in) %capalize: Captalize each word of a given sentence % Usage: out = captalize(in) % Multiple spaces are reduced to a single space too. % Roger Jang 20000723 if nargin<1, selfdemo; return; end if isempty(in), out = ''; return; end i = 1; [token, rem] = strtok(in); while ~isempty(token) extracted{i} = token; i = i+1; [token, rem] = strtok(rem); end for i = 1:length(extracted), string = extracted{i}; new_string = [upper(string(1)), string(2:end)]; extracted{i} = new_string; end out = extracted{1}; for i = 2:length(extracted), out = [out, ' ', extracted{i}]; end % ====== Self demo function selfdemo input = 'this is A test for Me too'; output = feval(mfilename, input); fprintf('input = %s\n', input); fprintf('output = %s\n', output);

  2. 請寫一個函數 isbig5.m,可以判斷給定的字串中,有哪幾個字元是屬於大五碼的常用字。例如 isbig5('我是Roger') 應該傳回的答案是 [1 1 0 0 0 0 0],代表前兩個字元是大五碼常用字,而後五個字元不是。請注意:常用的大五碼的內碼範圍是介於(含) 'A440' 和 'C67E' 之間。

    Hint
    可使用 hex2dec 指令。

    10-字元與字串/isbig5.mfunction out = isbig5(str) % isbig5: 測試字串是否為大五碼常用字 % Roger Jang, 20030518 % 假設送進來的字串已經經過了 xlate 的處理 out = (hex2dec('a440') <= str) & (str <= hex2dec('c67e'));

  3. 請寫一個函數 split.m,可以將一個字串,依照給定的分界字元(Delimiter),猜解成一個字串異值陣列,其用法如下:
    outputStr = split(string, delimiter)
    其中 string 是輸入字串,delimiter 是分界字元,輸出 output 則是一個由字串形成的異值陣列。例如,split('This-is-a-test', '-') 所產生的結果是 {'This', 'is', 'a', 'test'}。

    10-字元與字串/split.mfunction tokenList = split(str, delimiter) % split: Split a string based on a given delimiter % Usage: % tokenList = split(str, delimiter) % See also JOIN. % Roger Jang, 20010324 if nargin==0; selfdemo; return; end tokenList = {}; remain = str; i = 1; while ~isempty(remain), [token, remain] = strtok(remain, delimiter); tokenList{i} = token; i = i+1; end function selfdemo str='This-is-a-test'; tokenList=feval(mfilename, str, '-'); str fprintf('After running "tokenList=split(str, ''-'')":\n'); tokenList

  4. 中文的大五碼是由兩個位元組所構成,但不幸的是,在當初編碼的過程中,可能考慮欠周詳,因此把「直槓」("|")也編成某些字的大五碼的一部份,因此造成在自串處理上的極大不方便。(例如 Perl 的 Regular Expressions 碰到含有一直槓的大五碼就會出問題;使用 ODBC 來執行 SQL Command 時,若碰到含有一直槓的大五碼,也會出問題。此外,若用這些出問題的大五碼來當檔案或目錄名稱,則在使用 FTP 來進行檔案傳輸時,也會遇到麻煩而無法傳輸。)請寫一段 MATLAB 程式 big5withVerticalBar.m,來印出含有一直槓的所有中文字。 請問共有幾個這樣的中文字?請注意:常用的大五碼的內碼範圍是介於(含) 'A440' 和 'C67E' 之間。

    Hint
    舉個例子來說,「會」這個字是由兩個byte組成(B7 和 7C),把 B77C 轉成十進位就變成46972,的確是落在上述的Big5範圍之內,而「7C」就是題目裡面提到「直槓」的ASCII 內碼,所以只要在大五碼常用字的範圍內,找含有「7C」這個 byte的中文字,就是答案。

    10-字元與字串/big5withVerticalBar.m% 找出包含 "|" 的大五碼中文字 % Roger Jang, 20040425 range=hex2dec('a440'):hex2dec('c67e'); offendingChar='|'; k=0; for i=1:length(range) numRep=i-1+range(1); % fprintf('%d/%d ===> %s\n', i, length(range), char(numRep)); strRep=dec2hex(numRep); if hex2dec(strRep(1:2))==abs(offendingChar) | hex2dec(strRep(3:4))==abs(offendingChar) k=k+1; %fprintf('"%s" = "%s" + "%s"\n', char(numRep), char(hex2dec(strRep(1:2))), char(hex2dec(strRep(3:4)))); fprintf('%d. %s\n', k, char(numRep)); end end fprintf('大五碼常用字中,共有 %d 個字會包含「%s」的內碼!\n', k, offendingChar);

  5. 同樣的,如果大五碼的中文字包含「反斜線」("\"),也會出現許多問題。請仿造上一題,寫一個 MATLAB 程式 big5withBackSlash.m,列出所有包含反斜線的大五碼中文字。共有幾個?(做完這題之後,你就會知道為什麼許如芸和許志安的 MP3 歌曲檔案名稱,都不會出現「許」這個字了!)

    10-字元與字串/big5withBackSlash.m% 找出包含 "\" 的大五碼中文字 % Roger Jang, 20040425 range=hex2dec('a440'):hex2dec('c67e'); offendingChar='\'; k=0; for i=1:length(range) numRep=i-1+range(1); % fprintf('%d/%d ===> %s\n', i, length(range), char(numRep)); strRep=dec2hex(numRep); if hex2dec(strRep(1:2))==abs(offendingChar) | hex2dec(strRep(3:4))==abs(offendingChar) k=k+1; %fprintf('"%s" = "%s" + "%s"\n', char(numRep), char(hex2dec(strRep(1:2))), char(hex2dec(strRep(3:4)))); fprintf('%d. %s\n', k, char(numRep)); end end fprintf('大五碼常用字中,共有 %d 個字會包含「%s」的內碼!\n', k, offendingChar);

  6. 請寫一個 MATLAB 函數 rowCount.m,可以計算在一個字串二維陣列中,每一個字串出現的次數,其用法如下: [rows, count] = rowCount(A) 例如,當 A=['cd '; 'ab '; 'abc'; 'ab '; 'cd '; 'ab '; 'de '] 時,所得到的 rows 是 ['ab '; 'cd '; 'de '; 'abc'],count 是 [3; 2; 1; 1],代表在字串陣列 A 中,'ab ' 出現 3 次,'cd ' 出現 2 次,'de ' 出現 1 次,'abc' 出現 1 次。

    10-字元與字串/rowCount.mfunction [uniq_row, count] = rowCount(A) % rowCount: Unique row counts for a given matrix. % [uniq_row, count] = rowCount(A) % A: input matrix where each row is viewed as an "element" % uniq_row: sorted listing of unique row in A % count: counts for each returned unique row % % If A is a cell array of strings, then the output uniq_row is also a % cell array of strings. % % Roger Jang, 19981125, 20071205 if nargin<1, selfdemo; return, end if isempty(A), uniq_row=[]; count=[]; return; end cellstr_input = 0; if iscellstr(A), A = char(A); cellstr_input = 1; end term = sortrows(A); tmp1 = term; tmp1(end+1, :) = tmp1(end, :) + 1; tmp2 = tmp1(1:end-1, :) - tmp1(2:end, :); index = find(sum(abs(tmp2), 2) ~= 0); uniq_row = term(index, :); count = diff([0; index]); % Rearrange according to decending order of counts [count, index] = sort(count); count = flipud(count); index = flipud(index); uniq_row = uniq_row(index, :); % Return cell array of string if given cell array of string if cellstr_input, uniq_row = cellstr(uniq_row); end % ========== Subfunction ========== function selfdemo A = [ '一台';... '八爪'; ... '三光'; ... '人性'; ... '八爪'; ... '三光'; ... '八爪']; fprintf('Original string matrix:\n'); disp(A); fprintf('After sorting and finding counts of unique rows:\n'); [uniq_row, count] = feval(mfilename, A); for i = 1:length(count), fprintf('%s ==> %g\n', uniq_row(i, :), count(i)); end fprintf('Original cell array of strings:\n'); A = {'abc';'acd';'ad';'a';'bc';'ad';'acd';'acd'}; disp(A); [uniq_row, count] = feval(mfilename, A); fprintf('After sorting and finding counts of unique rows:\n'); for i = 1:length(count), fprintf('%s ==> %g\n', uniq_row{i}, count(i)); end

  7. 請寫一個 MATLAB 函數 str2ngram.m,可以傳回在一個輸入字串中,所存在的「n-字詞」,其用法如下:
    ngramArray = str2ngram(string, n)
    當 n = 2 時,此函數可以傳回由「二字詞」(Bigrams,任何相鄰兩個字即構成一個二字詞)所形成的字串陣列,當 n = 3 時,此函數可以傳回由「三字詞」(Trigrams,任何相鄰三個字即構成一個二字詞)所形成的字串陣列,依此類推。例如,str2ngram('網路上的芳鄰', 3) 所傳回的字串陣列是是 ['網路上'; '路上的'; '上的芳'; '的芳鄰']。

    10-字元與字串/str2ngram.mfunction ngram = str2ngram(str, n) % str2ngram: Extract n-gram from a given string or cell string % Usage: ngram = str2ngram(str, n) % str: a single string or a cell string % Roger Jang, 20030517 if nargin<1; selfdemo; return; end if nargin<2; n=2; end if isstr(str) ngram=char(buffer2(str, n, n-1)'); end if iscell(str) ngram=[]; for i=1:length(str) ngram=[ngram; str2ngram(str{i}, n)]; end end % ====== Sub-function function out = buffer2(y, frameSize, overlap) % BUFFER2 Frame blocking % This is almost the same as "buffer" except that there is no leading zeros % Roger Jang, 20010908 y = y(:); step = frameSize-overlap; frameCount = floor((length(y)-overlap)/step); out = zeros(frameSize, frameCount); for i=1:frameCount, startIndex = (i-1)*step+1; out(:, i) = y(startIndex:(startIndex+frameSize-1)); end % ====== Self demo function selfdemo str = {'網路上的芳鄰', '清華大學ABCD'}; for i=1:length(str) fprintf('str{%d}=%s\n', i, str{i}); end trigram = feval(mfilename, str, 3); fprintf('Trigram of the above string is: \n'); disp(trigram);

  8. 計算本書光碟片中有一個文字檔案 news.txt,包含了大約六千則新聞。請寫一段 MATLAB 程式 getNgramStat.m, 讀入 news.txt,並列出最常出現的 10 個二字詞及其出現次數,請將結果按出現次數由高而低來印出。請對「三字詞」、「四字詞」及「四字詞」進行類似的運算。(請注意:在進行統計時,這些 n-字詞不能包含大五碼的標點符號,也不能包含英文字母。)

    Hint
    你最好使用前面幾題的函數,才能事半功倍。

    10-字元與字串/getNgramStat.m% 統計 n-gram (bigram, trigram 等)在一篇文章出現的次數 filename='tangPoem3223.txt'; string=fileread(filename); string=string(string>255); for n=2:5 fprintf('Collect %g-grams...\n', n); ngram=str2ngram(string, n); fprintf('Sort %g %g-grams...\n', size(ngram,1), n); [uniqNgram, count] = countrows(ngram); fprintf('Display %d distinct n-grams according to counts...\n', size(uniqNgram,1)); for i = 1:10 fprintf('%d/%d: %s ===> %g\n', i, size(uniqNgram,1), uniqNgram(i, :), count(i)); end end

Part 2

  1. Palindrome: 「迴文」 (Palindrome) 在中文當中是指倒正著念和反著念都相同的句子,前後對稱,例如「上海自來水來自海上」。在英文當中是指正著看和反著看都相同的單字,例如「 madam 」。請寫一個 MATLAB 函數,來決定所給定的字串是否是「迴文」。
  2. Determine if a path is absolute: 請設計一個函數,可以用來判斷所給定的字串是不是代表一個絕對路徑。例如,'\users\jang' 或 '/windows' 或 'c:\windows' 都是絕對路徑,而 'abc.txt' 或 './abc.txt' 或 '..\abc.txt' 都是相對路徑。
  3. Convert a given path to be an absolute path: 請設計一個函數,可以用來將所給定的相對路徑轉成一個絕對路徑。

MATLAB程式設計:入門篇