参观Golang练习:rot13Reader

时间:2015-07-28 06:53:11

标签: go

我正在尝试解决Golang巡回练习rot13Reader

这是我的解决方案:

package main

import (
    "io"
    "os"
    "strings"
)

type rot13Reader struct {
    r io.Reader
}

func rot13(x byte) byte {
    switch {
    case x >= 65 && x <= 77:
        fallthrough
    case x >= 97 && x <= 109:
        x = x + 13
    case x >= 78 && x <= 90:
        fallthrough
    case x >= 110 && x >= 122:
        x = x - 13
    }
    return x
}

func (r13 *rot13Reader) Read(b []byte) (int, error) {
    n, err := r13.r.Read(b)
    for i := 0; i <= n; i++ {
        b[i] = rot13(b[i])
    }
    return n, err
}

func main() {
    s := strings.NewReader("Lbh penpxrq gur pbqr!")
    r := rot13Reader{s}
    io.Copy(os.Stdout, &r)
}

它返回You prnpxrq tur poqr!,这意味着只有“Lbh penpxrq gur pbqr!”的第一个单词。破了。我该如何破解整个句子?

16 个答案:

答案 0 :(得分:11)

修改

基本上你的解决方案很好并且有效,你输错了1个字符:

case x >= 110 && x >= 122:

将其更改为:

case x >= 110 && x <= 122:

您的输入和输出:

Lbh penpxrq gur pbqr!
You prnpxrq tur poqr!

每个词都有变化。问题不在于只有第一个字被读取和解码,问题在于你的解码算法。

ROT13中如果移位超出字母范围,则必须从字母表的开头(或结尾处)开始。例如,转移'N'将为'Z' + 1,因此它将成为'A',即第一个字母。看到这个简单的字符映射:

ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz
NOPQRSTUVWXYZABCDEFGHIJKLMnopqrstuvwxyzabcdefghijklm

所以你应该做的是在移动13之后,如果字母超出字母表,将其移动-26(英文字母中的字母数),这会产生预期效果(在最后一个之后)你从第一个继续写的信。)

示例解决方案:

func rot13(x byte) byte {
    capital := x >= 'A' && x <= 'Z'
    if !capital && (x < 'a' || x > 'z') {
        return x // Not a letter
    }

    x += 13
    if capital && x > 'Z' || !capital && x > 'z' {
        x -= 26
    }
    return x
}

及其输出:

You cracked the code!

Go Playground上尝试。

答案 1 :(得分:3)

您也可以使用:

func rot13(x byte) byte {
    input := []byte("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz")
    output := []byte("NOPQRSTUVWXYZABCDEFGHIJKLMnopqrstuvwxyzabcdefghijklm")
    match := bytes.Index(input, []byte{x})
    if match == -1 {
        return x
    }
    return output[match]
}

答案 2 :(得分:2)

我更喜欢在rot13函数中直接操作整数

contoso.com
www.contoso.com
http://www.contoso.com
http://contoso.com 

答案 3 :(得分:2)

package main

import (
    "io"
    "os"
    "strings"
)

type rot13Reader struct {
    r io.Reader
}

func (rot *rot13Reader) Read(b []byte) (int, error) {
    n, err := rot.r.Read(b)
    if err == io.EOF {
        return 0, err
    }

    for i := range b {
        var base byte
        if b[i] >= 'a' && b[i] <= 'z' {
            base = 'a'
        } else if b[i] >= 'A' && b[i] <= 'Z' {
            base = 'A'
        } else {
            continue
        }
        b[i] = (((b[i] - base) + 13) % 26) + base
    }
    return n, err
}

func main() {
    s := strings.NewReader("Lbh penpxrq gur pbqr!")
    r := rot13Reader{s}
    io.Copy(os.Stdout, &r)
}

答案 4 :(得分:1)

问题是您的功能无法正常工作。要验证这一点,只需尝试在"Lbh penpxrq Lbh gur pbqr!"上运行您的功能。如您所见,第一个单词被解码(以及第三个单词)。所以这意味着你的函数不仅仅运行在第一个单词上,而实际上运行在所有单词上(只是碰巧没有其他任何东西被改变)。

func (rot *rot13Reader) Read(p []byte) (n int, err error) {
    n, err = rot.r.Read(p)
    for i := 0; i < len(p); i++ {
        if (p[i] >= 'A' && p[i] < 'N') || (p[i] >='a' && p[i] < 'n') {
            p[i] += 13
        } else if (p[i] > 'M' && p[i] <= 'Z') || (p[i] > 'm' && p[i] <= 'z'){
            p[i] -= 13
        }
    }
    return
}

这是 Playground 。代码取自here

答案 5 :(得分:1)

我的代码也有效,它更简单!

func (rd *rot13Reader) Read(b []byte) (int, error) {
    m := make(map[byte]byte)
    input := "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
    output := "NOPQRSTUVWXYZABCDEFGHIJKLMnopqrstuvwxyzabcdefghijklm"
    for idx := range input {
        m[input[idx]] = output[idx]
    }

    n, err := rd.r.Read(b)
    for i := 0; i < n; i++ {
        if val, ok := m[b[i]]; ok {
          b[i] = val
        }
    }
    return n, err
}

答案 6 :(得分:1)

func rot13(x byte) byte {
    if (x >=  'A' && x <= 'M') || (x >=  'a' && x <= 'm') {
        return x + 13
    } else if (x >=  'N' && x <= 'Z') || (x >=  'n' && x <= 'z') {
        return x - 13
    } else {
        return x
    }
}

答案 7 :(得分:1)

还有另一种方法:

func (rr *rot13Reader) Read(b []byte) (int, error) {
    n, err := rr.r.Read(b)
    if err != nil {
        return 0, err
    }
    for i := 0; i < n; i++ {
        if b[i] >= 'A' && b[i] <= 'z' {
            b[i] += 13
            if b[i] > 'z' {
                b[i] -= 26
            }
        }
    }
    return n, nil
}

答案 8 :(得分:0)

作为@icza的答案的后续,而不是硬编码检查字节是否是字母的,而是创建一个小函数来确定它。它使代码更清晰。

func alphabetic(x byte) bool {
    return (x >= 'A' && x <='Z') || (x >= 'a' && x <= 'z')
}

func capital(x byte) bool {
    return x >= 'A' && x <= 'Z'
}

func rot13(x byte) byte {
    // byte isn't a letter
    if !alphabetic(x) {
        return x
    }

    original_is_capital := capital(x)

    // apply rot13  
    x += 13

    // the new letter should loop around
    if !alphabetic(x) || original_is_capital {
        x -= 26
    }

    return x
}

答案 9 :(得分:0)

自问题问题已经过去了两年,但我想分享我的代码,这个代码与之相比非常简单。

You-cracked-the-code.

结果? {{ range $.Site.Languages }} <span href="#"> {{ .Lang }} - {{ .LanguageName }} </span> {{ end }} 当然,实施所有ascii规模会更好,但它仍然可以完成大部分工作。

答案 10 :(得分:0)

func (reader rot13Reader) Read(bytes []byte) (int, error) {
    n, err := reader.r.Read(bytes)
    for i, val := range bytes[:n] {
        if val >= 'a' && val <= 'z' {
            bytes[i] = (val-'a'+13)%26 + 'a'
        } else if val >= 'A' && val <= 'Z' {
            bytes[i] = (val-'A'+13)%26 + 'A'
        }
    }
    return n, err
}

答案 11 :(得分:0)

这是我解决的方法:

package main

import (
    "io"
    "os"
    "strings"
)

type rot13Reader struct {
    r io.Reader
}

func rot13(r byte) byte {
    sb := rune(r)
    if sb >= 'a' && sb <= 'm' || sb >= 'A' && sb <= 'M' {
        sb = sb + 13
    }else if sb >= 'n' && sb <= 'z' || sb >= 'N' && sb <= 'Z' {
        sb = sb - 13
    }
    return byte(sb)

}

func (r13 *rot13Reader) Read(b []byte) (i int, e error) {
    n, err := r13.r.Read(b)
    for i := 0; i <= n; i++ {
        b[i] = rot13(b[i])
    }
    return n, err
}

func main() {
    s := strings.NewReader("Lbh penpxrq gur pbqr!")
    r := rot13Reader{s}
    io.Copy(os.Stdout, &r)
}

答案 12 :(得分:0)

这是我的两分钱

(请注意,“ Z” ASCII码是90,而“ h”是114)

func (r rot13Reader) Read(p []byte) (n int, err error) {
    n, err = r.r.Read(p)
    if err == nil {
        for i := range p {
            if c := p[i] + 13; c > 'z' || (c > 'Z' && c < 'h') {
                p[i] = c - 26
            } else {
                p[i] = c
            }
        }
    }
    return n, err
}

答案 13 :(得分:0)

一个简单的代码段,可更改字母并忽略其他字符

func (rot *rot13Reader) Read(b [] byte) (int, error) {
    size,e := rot.r.Read(b)
    for i := 0; i < size; i++ {
        if b[i] < byte('A') || b[i] > byte('z') {
            continue
        }
        if b[i] > byte('a') {
            b[i] = byte('a') + (b[i] - byte('a') + 13)%26
        } else {
            b[i] = byte('A') + (b[i] - byte('A') + 13)%26
        }
    }
    return size, e
}

答案 14 :(得分:-1)

我的尝试:

package main

import (
    "io"
    "os"
    "strings"
)

type rot13Reader struct {
    io.Reader
}

func (r rot13Reader) Read(p []byte) (n int, err error) {
    n, _ = r.Reader.Read(p)
    for i := 0; i < n; i++ {
        if p[i] != byte(' ') {
            if p[i] > byte('m') {
                p[i] = p[i] - 13
            } else {
                p[i] = p[i] + 13
            }
        }
    }
    err = io.EOF
    return
}

func main() {
    s := strings.NewReader("Lbh penpxrq gur pbqr!")
    r := rot13Reader{s}
    _, _ = io.Copy(os.Stdout, &r)
}

答案 15 :(得分:-1)

我的解决方法是这样:

func rot13(b byte) byte {
    in := []byte("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz")
    out := []byte("NOPQRSTUVWXYZABCDEFGHIJKLMnopqrstuvwxyzabcdefghijklm")

    for i, v := range in {
        if v == b {
            return out[i]
        }
    }

    return b
}

type rot13Reader struct {
    r io.Reader
}

func (rot *rot13Reader) Read(b []byte) (int, error) {
    n, err := rot.r.Read(b)

    for i := range b {
        b[i] = rot13(b[i])
    }

    return n, err
}