【问题标题】:Common Lisp: "no non-white-space characters in string"Common Lisp:“字符串中没有非空白字符”
【发布时间】:2012-07-18 18:38:10
【问题描述】:

对于 Project Euler Problem 8,我被告知要解析一个 1000 位数字。 这是一个蛮力的 Lisp 解决方案,它基本上每 5 个连续的数字进行一次,并从头到尾将它们相乘,并在循环结束时返回最大的一个。

代码:

(defun pep8 ()
  (labels ((product-of-5n (n)
         (eval (append '(*)
               (loop for x from n to (+ n 5)
                collect (parse-integer
                1000digits-str :start x :end (+ x 1)))))))
    (let ((largestproduct 0))
      (do ((currentdigit 0 (1+ currentdigit)))
          ((> currentdigit (- (length 1000digits-str) 6)) (return largestproduct))
        (when (> (product-of-5n currentdigit) largestproduct)
          (setf largestproduct (product-of-5n currentdigit)))))))

它编译时没有任何警告,但在运行时我得到:

no non-whitespace characters in string "73167176531330624919225119674426574742355349194934...".
   [Condition of type SB-INT:SIMPLE-PARSE-ERROR]

我检查了本地函数 product-of-5n 是否正在工作,方法是再次将其编写为全局函数:

(defun product-of-5n (n)
  (eval (append '(*)
        (loop for x from n to (+ n 5)
           collect (parse-integer
                1000digits-str :start x :end (+ x 1))))))

编译时没有警告,运行时似乎运行良好。例如,

CL_USER> (product-of-5n 1) => 882

这似乎是正确的,因为前五个数字是 7、3、1、6 和 7。

至于1000digits-str,它只是用defvar编译的,而用Emacs的longlines-show-hard-newlines,我不认为字符串中有任何空白字符,因为这就是 SBCL 所抱怨的,对吧?

【问题讨论】:

  • 使用 EVAL 是不好的。尝试替换它。

标签: lisp common-lisp sbcl


【解决方案1】:

我不认为字符串中有任何空白字符,因为这就是 SBCL 所抱怨的,对吧?

错误消息不是抱怨 white-space存在,而是抱怨 non-space 的 absence空白。但这实际上有点误导:消息 应该 说的是要解析的特定子字符串中没有非空白。这是因为你跑完了字符串的末尾,所以解析了一个零长度的子字符串。

另外,product-of-5n 的定义并不完全正确。 (product-of-5n 1) 返回前五位数字的乘积只是偶然的。字符串从0 开始索引,所以(product-of-5n 1)second 字符开头;并且函数从n + 0迭代到n + 5,一共六个字符;所以(product-of-5n 1) 返回 3 × 1 × 6 × 7 × 1 × 7,恰好和 7 × 3 × 1 × 6 × 7 × 1 一样。

【讨论】:

  • 当我写 (product-of-5n 1) 时,我就知道出了点问题……但已经很晚了,我没有费心用 0 尝试它。感谢您阐明 SBCL 的真正含义抱怨!
【解决方案2】:

EVAL 不是个好主意。

您的循环上限错误。

否则我用数字字符串尝试它,它可以工作。

它也是欧拉 8,而不是 9。

这是我的版本:

(defun euler8 (string)
  (loop for (a b c d e) on (map 'list #'digit-char-p string)
        while e maximize (* a b c d e)))

【讨论】:

【解决方案3】:

由于我不了解常见的 lisp,因此我稍微修改了您的代码以适应 elisp。至于发现错误,除了已经说过的((product-of-5n 1) 应该返回 126),我唯一的评论是在(pep8) 中,使用 length-4 而不是 -6(否则你会丢失最后 2 个字符)。抱歉,我不知道如何解决您的解析错误(我改用 string-to-number),但如果您觉得它有用,这里是代码:

(defun product-of-5n (n)       ;take 5 characters from a string "1000digits-str" starting with nth one and output their product
  (let (ox)                    ;define ox as a local variable
    (eval                      ;evaluate
     (append '(*)              ;concatenate the multiplication sign to the list of 5 numbers (that are added next)
         (dotimes (x 5 ox)     ;x goes from 0 to 4 (n is added later to make it go n to n+4), the output is stored in ox
           (setq ox (cons      ;create a list of 5 numbers and store it in ox 
             (string-to-number 
              (substring 1000digits-str (+ x n) (+ (+ x n) 1) ) ;get the (n+x)th character  
              )                ;end convert char to number
             ox )              ;end cons
             )                 ;end setq
           )                   ;end dotimes, returns ox outside of do, ox has the list of 5 numbers in it
         )                     ;end append
     )                         ;end eval
    )                          ;end let
  )

(defun pep8 () ;print the highest 
  (let ((currentdigit 0) (largestproduct 0))                    ;initialize local variables
    (while  (< currentdigit  (- (length 1000digits-str) 4)    ) ;while currentdigit (cd from now on) is less than l(str)-4
      ;(print (cons "current digit" currentdigit))              ;uncomment to print cd
      (when (> (product-of-5n currentdigit) largestproduct)     ;when current product is greater than previous largestproduct (lp)
      (setq largestproduct (product-of-5n currentdigit))        ;save lp
      (print (cons "next good cd" currentdigit))                ;print cd
      (print (cons "with corresponding lp" largestproduct))     ;print lp
      )                                                         ;end when
    (setq currentdigit (1+ currentdigit))                       ;increment cd
    )                                                           ;end while
    (print (cons "best ever lp" largestproduct) )               ;print best ever lp
    )                                                           ;end let
  )

(setq 1000digits-str "73167176531330624919")
(product-of-5n 1)
(pep9)

返回(在前 20 个字符上运行时)

"73167176531330624919"
126 

("next good cd" . 0)
("with corresponding lp" . 882)

("next good cd" . 3)
("with corresponding lp" . 1764)

("best ever lp" . 1764)

【讨论】:

  • 原来问题只是我在 product-of-5n 中设置的上限错误,并且 length - 4 不起作用,因为我正在解析 5 位乘以 5 位的数字,并且所以长度 - 4 意味着我在数字 996 处结束解析,我尝试到达数字 1001,但实际上我只有 1000。
【解决方案4】:

我前段时间做过这个问题,你在问题​​描述中缺少一件事。您需要将 consequent 读取为从 any 偏移量开始,而不仅仅是可被 5 整除的偏移量。因此,问题的解决方案将更像以下内容:

(defun pe-8 ()
  (do ((input  (remove #\Newline
"73167176531330624919225119674426574742355349194934
96983520312774506326239578318016984801869478851843
85861560789112949495459501737958331952853208805511
12540698747158523863050715693290963295227443043557
66896648950445244523161731856403098711121722383113
62229893423380308135336276614282806444486645238749
30358907296290491560440772390713810515859307960866
70172427121883998797908792274921901699720888093776
65727333001053367881220235421809751254540594752243
52584907711670556013604839586446706324415722155397
53697817977846174064955149290862569321978468622482
83972241375657056057490261407972968652414535100474
82166370484403199890008895243450658541227588666881
16427171479924442928230863465674813919123162824586
17866458359124566529476545682848912883142607690042
24219022671055626321111109370544217506941658960408
07198403850962455444362981230987879927244284909188
84580156166097919133875499200524063689912560717606
05886116467109405077541002256983155200055935729725
71636269561882670428252483600823257530420752963450"))
       (tries 0 (1+ tries))
       (result 0))
      ((= tries 5) result)
    (setq result
          (max result
               (do ((max 0)
                    (i 0 (+ 5 i)))
                   ((= i (length input)) max)
                 (setq max
                       (do ((j i (1+ j))
                            (current 1)
                            int-char)
                           ((= j (+ 5 i)) (max current max))
                         (setq int-char (- (char-code (aref input j)) 48))
                         (case int-char
                           (0 (return max))
                           (1)
                           (t (setq current (* current int-char))))))))
          input (concatenate 'string (subseq input 1) (subseq input 0 1)))))

这有点难看,但它说明了这个想法。

编辑对不起,我混淆了你的两个功能。所以那个like是不正确的。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-07-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-06-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多