2012-12-03 74 views
2

我想寫的是,在下面的方式檢查中的關鍵字參數存在口齒不清

(defun hyphenate (string &key upper lower) 
    (do ((s (cdr (coerce string 'list)) (cdr s)) 
     (acc (string (char string 0)))) 
     ((null s) (cond 
       (lower (string-downcase acc)) 
       (t (string-upcase acc)))) 
    (cond 
     ((upper-case-p (car s)) (setf acc (concatenate 'string 
                (concatenate 'string acc "-") 
                (string (car s))))) 
     (t (setf acc (concatenate 'string acc (string (car s))))))))) 

基本上,如果函數接收的關鍵字上,它會調用字符串通過關鍵字參數傳遞給函數的函數-upcase,並且如果它接收到較低的密鑰,它將執行一個字符串downcase。

我只是不知道什麼適當的方式來測試這些參數是在我的功能。我不想將它們綁定到一個值。我只是想打電話給他們這樣

(斷字「jobPostings」:上)

如何檢查的存在:上在函數調用?它一直告訴我有一個「不成對的關鍵字傳遞給連字符」

+0

爲什麼這不綁定我的關鍵字參數?!?! –

回答

1

如果我理解正確,你想要這樣的東西,對吧?

(ql:quickload "cl-ppcre") 
(defun hyphenate (string &key (transform-case #'identity)) 
    (reduce 
    #'(lambda (a b) 
     (concatenate 'string a (when (> (length a) 0) "-") 
        (funcall transform-case b))) 
      (cl-ppcre:split "(?=[A-Z])" string) :initial-value "")) 

(hyphenate "fooBarBaz") 
"foo-Bar-Baz" 

(hyphenate "fooBarBaz" :transform-case #'string-downcase) 
"foo-bar-baz" 

這也是不太consing /脅迫,你可以寫更多的轉換函數做一些與字符,如音譯他們或任何你喜歡的。

如果你的主要論點是不是一個功能,你可以做一些這樣的效果:

(ccase key-argument 
    (possilbe-value-0 (do what possible value 0 does)) 
    (possilbe-value-1 (do what possible value 1 does)) 
    . . . 
    (possilbe-value-N (do what possible value N does))) 

例如,但真的有很多方法可以做到這一點。


相似,但W/O ppcre:

(defun hyphenate (string &key (case-transform #'identity)) 
    (with-output-to-string (stream) 
    (loop for c across string 
     do (if (upper-case-p c) 
       (progn 
       (when (> (file-position stream) 0) 
        (write-char #\- stream)) 
       (write-char (funcall case-transform c) stream)) 
       (write-char c stream))))) 

(hyphenate "fooBarBaz") 
"foo-Bar-Baz" 

(hyphenate "fooBarBaz" :case-transform #'char-downcase) 
"foo-bar-baz" 
6

關鍵字作爲參數,並關鍵字參數是兩個不同的東西。 關鍵字參數是命名參數。他們來作爲兩項:a 名稱

像這樣:

CL-USER 1 > (defun hyphenate (string &key upper lower) (list string upper lower)) 
HYPHENATE 

你需要給一個名字和一個值。請注意,未傳入的關鍵字參數的值爲NIL。

CL-USER 2 > (hyphenate "foo" :upper t) 
("foo" T NIL) 

相比之下,與可選參數:

CL-USER 3 > (defun hyphenate (string &optional case) (list string case)) 
HYPHENATE 

現在你只需要給出可選參數,可以是符號:upper

CL-USER 4 > (hyphenate "foo" :upper) 
("foo" :UPPER) 

還是你要用一個關鍵字參數,你的情況下符號傳遞:

CL-USER 5 > (defun hyphenate (string &key case) (list string case)) 
HYPHENATE 

同樣,由於兩個項目:一個名稱和值:

CL-USER 6 > (hyphenate "foo" :case :upper) 
("foo" :UPPER) 

一些關於您的功能的評論:

  • 如果檢查謂詞,請使用IF,而不是COND

  • 您正在迭代字符串並首先將其轉換爲字符串。通常你會使用索引遍歷字符串。

  • 您將單個字符連接到DO循環中的字符串。這很醜陋。如果您已經在使用輸入列表,爲什麼不使用輸出列表並在退出時將其轉換回字符串?

如果你想保持使用列表的想法,你想要在列表中映射。

(defun hyphenate (string &key (case :upper)) 
    (map 'string 
     (if (eq case :upper) #'char-upcase #'char-downcase) 
     (destructuring-bind (start . rest) 
      (coerce string 'list) 
     (cons start 
       (mapcan (lambda (char) 
         (if (upper-case-p char) 
          (list #\- char) 
          (list char))) 
         rest))))) 

MAPCAN插入必要的連字符。外部MAP轉換大小寫並返回一個字符串。

2

這不是關鍵字參數工作的方式。

有鑑於此:

(defun hyphenate (string &key upper lower) 
    ...) 

你會調用它是這樣的:

> (hyphenate "fooBar" :lower t) 
"foo-bar" 
> (hyphenate "fooBar" :upper t) 
"FOO-BAR" 
> (hyphenate "fooBar") 
"FOO-BAR" 
> (hyphenate "fooBar" :upper t :lower t) 
"foo-bar" 
> (hyphenate "fooBar" :upper) 
ERROR: keyword argument list not of even length 
[1]> 

基本上,關鍵字參數給定爲必選和可選參數之後內嵌property list

也許你想要的是:

(defun hyphenate (string &optional (case :lower)) 
    (assert (member case '(:lower :upper))) 
    (let ((lower (eq case :lower))) 
    ...)) 

現在你這樣稱呼它:

> (hyphenate "fooBar" :lower) 
"foo-bar" 
> (hyphenate "fooBar" :upper) 
"FOO-BAR" 
> (hyphenate "fooBar") 
"foo-bar" 
> (hyphenate "fooBar" nil) 
ERROR: (assert (member nil '(:lower :upper))) failed 
[1]> 

你可能要重新考慮你的函數接受nil使任何情況下,函數被調用。但是由於我不知道如何使用它,這只是一個建議。

但是,還有其他的事情你應該考慮這個功能。

例如,您將原始字符串轉換爲列表。如果hyphenate經常被調用,您可能會注意到性能受到影響。如果你直接訪問原始字符串會更好。您可以預先分配新的字符串(make-string (+ (length string) num-hyphens))

最後,您可以使用nstring-upcase and nstring-downcase,因爲生成的字符串總是新鮮的。


PS:在Common Lisp的,有可能知道,如果一個可選或關鍵字參數是在參數的聲明中lambda list實際上提供了一個額外的變量:

(defun foo (string &optional (opt (default-opt-expression) opt-supplied-p)) 
    ...) 

(defun bar (string &key (key (default-key-expression) key-supplied-p)) 
    ...) 

在這些例子中,opt-supplied-pkey-supplied-p是布爾值,說明是否提供參數。