会计的优雅方式" A"将字符串转换为26-Ary和Back?

时间:2015-03-08 00:08:48

标签: scheme racket base hexavigesimal

我需要将字符串转换为26-ary,然后才能将它们转换回来。

我目前的代码是:

(define (26-ary-word s)
  (let ([len (string-length s)])
        (let f ([n 0]
                [acc (+
                      (- (char->integer (string-ref s 0)) 97)
                      1)]) ; adding 1 so that all strings start with 'b'
          (if (< n len)
              (f (add1 n) (+ (* acc 26) (- (char->integer (string-ref s n)) 97)))
              acc))))

(define (word-ary-26 n)
  (let f ([n (/ (- n (modulo n 26)) 26)]
          [acc (cons (integer->char (+ (modulo n 26) 97)) '())])
    (if (> n 0)
        (f (/ (- n (modulo n 26)) 26) (cons (integer->char (+ (modulo n 26) 97)) acc))
        (list->string (cdr acc))))) ; remove "b" from front of string

我添加1到acc开头,并删除结尾的“b”。这是因为将"a" - 97乘以26仍为0。

这已经很丑了,但它甚至都不起作用。当“z”位于第一个位置(26^2)时,“z”被记录为“701”,后者被翻译为“az”。

我可以添加另一个if子句来检测第一个字母是否为z,但这真的很难看。有没有办法解决这个问题呢?

          (if (and (= n 0) (= acc 26))
              (f (add1 n) 51)
              (f (add1 n) (+ (* acc 26) (- (char->integer (string-ref s n)) 97))))

这是我必须使用的丑陋边缘案件处理代码。

1 个答案:

答案 0 :(得分:1)

老实说,我并不完全确定你的代码在做什么,但无论哪种方式,它都要比它需要的复杂得多。通过使用一些高阶构造,将base-26字符串转换为整数非常简单:

; (char-in #\a #\z) -> (integer-in 0 25)
(define (base-26-char->integer c)
  (- (char->integer c) (char->integer #\a)))

; #rx"[a-z]+" -> integer?
(define (base-26-string->integer s)
  (let ([digits (map base-26-char->integer (string->list s))])
    (for/fold ([sum 0])
              ([digit (in-list digits)])
      (+ (* sum 26) digit))))

通过将问题分解为两个函数,一个转换单个字符和一个转换整个字符串的函数,我们可以轻松地利用Racket的string->list函数来简化实现。

逆转换实际上使用纯粹的功能构造变得更加优雅,但是使用额外的辅助函数变得极其微不足道了#34;爆炸&#34;任何基数中的整数。

; integer? [integer?] -> (listof integer?)
(define (integer->digits i [base 10])
  (reverse
   (let loop ([i i])
     (if (zero? i) empty
         (let-values ([(q r) (quotient/remainder i base)])
           (cons r (loop q)))))))

然后字符串生成函数的实现变得明显。

; (integer-in 0 25) -> (char-in #\a #\z)
(define (integer->base-26-char i)
  (integer->char (+ i (char->integer #\a))))

; integer? -> #rx"[a-z]+"
(define (integer->base-26-string i)
  (list->string (map integer->base-26-char (integer->digits i 26))))