-
Notifications
You must be signed in to change notification settings - Fork 26
Expand file tree
/
Copy pathrailfence.py
More file actions
96 lines (82 loc) · 3.56 KB
/
railfence.py
File metadata and controls
96 lines (82 loc) · 3.56 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
# -*- coding: UTF-8 -*-
"""Rail Fence Cipher Codec - rail fence content encoding.
This codec:
- en/decodes strings from str to str
- en/decodes strings from bytes to bytes
- decodes file content to str (read)
- encodes file content from str to bytes (write)
"""
from ..__common__ import *
__examples__ = {
'enc(rail_123|rail-2-123)': {'this is a test': None},
'enc(railfence|zigzag)': {'this is a test': "t ashsi etist"},
'enc(rail-5|zigzag_5)': {'this is a test': "tah istsiet s"},
'enc(rail_5-3|rail_5_3)': {'this is a test': "it sss etiath "},
'enc(rail-5-3-up|rail_5_3-up)': {'this is a test': "h tiats e ssit"},
'enc(rail-7-4|rail_7_4)': {'this is a test': "a stiet shsti"},
'dec(zigzag)': {'': ""},
}
__guess__ = ["railfence-%d" % i for i in range(1, 11)] + ["railfence-%d-up" % i for i in range(1, 11)]
def __build(text, rails, offset, up):
l, rail = len(text), offset
# set the starting rail and direction
if up:
dr = -1
rail = rails - offset - 1
else:
dr = 1
# create rails
f = [[None] * l for i in range(rails)]
# now zig-zag between rails
for x in range(l):
f[rail][x] = text[x]
if rail >= rails - 1:
dr = -1
elif rail <= 0:
dr = 1
rail += dr
return f
def __check(length, rails, offset):
if rails > length:
raise ParameterError("Bad parameter for encoding 'railfence': rails=%d (should be <= %d)" % (rails, length))
if offset > rails:
raise ParameterError("Bad parameter for encoding 'railfence': offset=%d (should be <= %d)" % (offset, rails))
def railfence_encode(rails, offset, up):
rails, offset, up = int(rails or 3), int(offset or 0), up is not None and up != ""
def encode(text, errors="strict"):
r, l = "", len(text)
__check(l, rails, offset)
f = __build(text, rails, offset, up)
for rail in range(rails):
for x in range(l):
if f[rail][x] is not None:
r += f[rail][x]
return r, l
return encode
def railfence_decode(rails, offset, up):
rails, offset, up = int(rails or 3), int(offset or 0), up is not None and up != ""
def decode(text, errors="strict"):
# this if block is particularly useful with Python2 ; see codecs.py at line 492 in comparison with codecs.py
# from Python3 at line 501: in Python2, a last block can be read while empty while in Python3 not
# as a consequence, in Python2, an error is triggered as an empty text cannot be decoded with Rail Fence with
# a rails parameter > 0 (see the __check(length, rails, offset)) function
if text == "":
return "", 0
r, i, l = "", 0, len(text)
__check(l, rails, offset)
f = __build("." * len(text), rails, offset, up)
# put the characters in the right place
for rail in range(rails):
for x in range(l):
if f[rail][x] == ".":
f[rail][x] = text[i]
i += 1
# read the characters in the right order
for x in range(l):
for rail in range(rails):
if f[rail][x] is not None:
r += f[rail][x]
return r, len(text)
return decode
add("railfence", railfence_encode, railfence_decode,
r"^(?:rail(?:[-_]?fence)?|zigzag)(?:[-_]([1-9]|[1-9]\d+)(?:[-_]([0-9]|[1-9]\d+))?(?:[-_](up))?)?$")