Introduction
This the fourth and last part of this recipe provides a few state machines for use with the validator.
North American Telephone Number State Machine
1 from StateMachine import EBadCharacter, StateMachine
2
3 def areacode ( self, token ) :
4
5 needClosingParen = False
6 if token == '(' :
7 needClosingParen = True
8 token = self . nextToken ( )
9 else :
10 self . allTokens . insert ( 0, '(' )
11 for c in range ( 3 ) :
12 if not token . isdigit ( ) : raise EBadCharacter ( )
13 token = self . nextToken ( )
14 if needClosingParen :
15 if token == ')' :
16 token = self . nextToken ( )
17 else : raise EBadCharacter ( )
18 else :
19 self . allTokens . insert ( len ( self . allTokens ) - 1, ')' )
20 if token == ' ' : token = self . nextToken ( )
21 else :
22 self . allTokens . insert ( len ( self . allTokens ) - 1, ' ' )
23 return 'exchange', token
24
25 def exchange ( self, token ) :
26
27 for c in range ( 3 ) :
28 if not token . isdigit ( ) : raise EBadCharacter ( )
29 token = self . nextToken ( )
30 if token == '-' : token = self . nextToken ( )
31 elif token == ' ' :
32 token = self . nextToken ( )
33 self . allTokens [ len ( self . allTokens ) - 2 ] = '-'
34 else :
35 self . allTokens . insert ( len ( self . allTokens ) - 1, '-' )
36 return 'local', token
37
38 def local ( self, token ) :
39
40 for c in range ( 4 ) :
41 if not token . isdigit ( ) : raise EBadCharacter ( )
42 if c < 3 : token = self . nextToken ( )
43 return 'complete', None
44
45 def complete ( self, token ) : pass
46
47 statemachine = StateMachine ( )
48 statemachine . addState ( areacode )
49 statemachine . addState ( exchange )
50 statemachine . addState ( local )
51 statemachine . addState ( complete, True )
52 statemachine . setStartState ( areacode )
Canadian Postal Code State Machine
1 from StateMachine import EBadCharacter, StateMachine
2
3 def local ( self, token ) :
4
5 if not token . isalpha ( ) : raise EBadCharacter ( )
6 token = self . nextToken ( )
7 if not token . isdigit ( ) : raise EBadCharacter ( )
8 token = self . nextToken ( )
9 if not token . isalpha ( ) : raise EBadCharacter ( )
10 token = self . nextToken ( )
11
12 if token == ' ' : token = self . nextToken ( )
13
14 if not token . isdigit ( ) : raise EBadCharacter ( )
15 token = self . nextToken ( )
16 if not token . isalpha ( ) : raise EBadCharacter ( )
17 token = self . nextToken ( )
18 if not token . isdigit ( ) : raise EBadCharacter ( )
19
20 return 'complete', None
21
22 def complete ( self, token ) : pass
23
24 statemachine = StateMachine ( )
25 statemachine . addState ( local )
26 statemachine . addState ( complete, True )
27 statemachine . setStartState ( local )
UK Postcode State Machine
1 from StateMachine import EBadCharacter, StateMachine
2
3 def postcodeFirstPart ( self, token ) :
4
5 firstToken = token
6 if not firstToken . isalpha ( ) : raise EBadCharacter ( )
7 secondToken = self . nextToken ( )
8 if secondToken . isalpha ( ) :
9 thirdToken = self . nextToken ( )
10 if thirdToken . upper ( ) == 'R' and secondToken . upper ( ) == 'I' and firstToken . upper ( ) == 'G' :
11 token = self . nextToken ( )
12 return "postcodeAfterBlank", token
13 self . pushToken ( )
14 else :
15 self . pushToken ( )
16 if not token . isalpha ( ) : raise EBadCharacter ( )
17 token = self . nextToken ( )
18 if not token . isdigit ( ) : raise EBadCharacter ( )
19 token = self . nextToken ( )
20 if token == ' ' : return "postcodeAfterBlank", token
21 if not token . isalnum ( ) : raise EBadCharacter ( )
22 token = self . nextToken ( )
23 if token != ' ' : raise EBadCharacter ( )
24 return "postcodeAfterBlank", token
25
26 def postcodeAfterBlank ( self, token ) :
27
28 if token != ' ' : raise EBadCharacter ( )
29 token = self . nextToken ( )
30 if not token . isdigit ( ) : raise EBadCharacter ( )
31 token = self . nextToken ( )
32 if not token . isalpha ( ) : raise EBadCharacter ( )
33 token = self . nextToken ( )
34 if not token . isalpha ( ) : raise EBadCharacter ( )
35 return 'complete', None
36
37 def complete ( self, token ) : pass
38
39 statemachine = StateMachine ( )
40 statemachine . addState ( postcodeFirstPart )
41 statemachine . addState ( postcodeAfterBlank )
42 statemachine . addState ( complete, True )
43 statemachine . setStartState ( postcodeFirstPart )
Zip Code State Machine
1 from StateMachine import EBadCharacter, StateMachine
2
3 def local ( self, token ) :
4
5 for c in range ( 5 ) :
6 if not token . isdigit ( ) : raise EBadCharacter ( )
7 if c < 4 : token = self . nextToken ( )
8 return 'complete', None
9
10 def complete ( self, token ) : pass
11
12 statemachine = StateMachine ( )
13 statemachine . addState ( local )
14 statemachine . addState ( complete, True )
15 statemachine . setStartState ( local )
Picture Processing State Machine
1 from StateMachine import EBadCharacter, BADCHARACTER, STRINGTOOLONG, OK, StateMachine
2
3 ##+ algebraic sign
4 ##9 digit only
5 ##A alphabetic only
6 ##N alphanumeric only
7 ##X anycharacter
8 ##Y Y or N only
9 ##? previous character not optional
10 ##all other characters in the picture literal
11
12 def local ( self, token ) :
13
14 picture = self . picture . upper ( )
15
16 optional = [ ]
17 for i, c in enumerate ( picture ) :
18 if c == '?' : optional [ -1 + len ( optional ) ] = True
19 else : optional . append ( False )
20 picture = picture . replace ( '?', '' )
21
22 for i, pictureChar in enumerate ( picture ) :
23 if pictureChar == 'A' and token . isalpha ( ) : pass
24 elif pictureChar == '9' and token . isdigit ( ) : pass
25 elif pictureChar == '+' and token in [ '+', '-', ] : pass
26 elif pictureChar == 'N' and token . isalnum ( ) : pass
27 elif pictureChar == 'Y' and token in [ 'Y', 'N', ] : pass
28 elif pictureChar == 'X' : pass
29 else :
30 if pictureChar in [ 'A', '9', '+', 'N', 'Y', 'X', ] :
31 if optional [ i ] : continue
32 else : raise EBadCharacter ( )
33 else :
34 if pictureChar == token : pass
35 else :
36 if optional [ i ] : continue
37 else : raise EBadCharacter ( )
38 if i + 1 < len ( picture ) :
39 token = self . nextToken ( )
40 else :
41 break
42
43 return 'complete', None
44
45 def complete ( self, token ) : pass
46
47 statemachine = StateMachine ( )
48 statemachine . addState ( local )
49 statemachine . addState ( complete, True )
50 statemachine . setStartState ( local )
51
52 if __name__ == "__main__" :
53
54 import unittest
55
56 class TestAgainstPostalCodes ( unittest . TestCase ) :
57
58 def test1 ( self ) :
59 statemachine . picture = 'a9a ?9a9'
60 self . assertEqual ( statemachine . testString ( 'N0A 1P0' ), OK )
61
62 def test2 ( self ) :
63 statemachine . picture = 'a9a ?9a9'
64 self . assertEqual ( statemachine . testString ( 'N0A1P0' ), OK )
65
66 def test3 ( self ) :
67 statemachine . picture = 'a9a ?9a9'
68 self . assertEqual ( statemachine . testString ( '-0A1P0' ), BADCHARACTER )
69
70 def test4 ( self ) :
71 statemachine . picture = 'a9a ?9a9'
72 self . assertEqual ( statemachine . testString ( '10A1P0' ), BADCHARACTER )
73
74 def test5 ( self ) :
75 statemachine . picture = 'a9a ?9a9'
76 self . assertEqual ( statemachine . testString ( 'NaA1P0' ), BADCHARACTER )
77
78 def test6 ( self ) :
79 statemachine . picture = 'a9a ?9a9'
80 self . assertEqual ( statemachine . testString ( 'N021P0' ), BADCHARACTER )
81
82 def test7 ( self ) :
83 statemachine . picture = 'a9a ?9a9'
84 self . assertEqual ( statemachine . testString ( 'N0AaP0' ), BADCHARACTER )
85
86 def test8 ( self ) :
87 statemachine . picture = 'a9a ?9a9'
88 self . assertEqual ( statemachine . testString ( 'N0A120' ), BADCHARACTER )
89
90 def test9 ( self ) :
91 statemachine . picture = 'a9a ?9a9'
92 self . assertEqual ( statemachine . testString ( 'N0A1Pz' ), BADCHARACTER )
93
94 def test10 ( self ) :
95 statemachine . picture = 'a9a ?9a9'
96 self . assertEqual ( statemachine . testString ( 'N0A1P00' ), STRINGTOOLONG )
97
98 def test11 ( self ) :
99 statemachine . picture = '+?999.?9?'
100 self . assertEqual ( statemachine . testString ( '-111.1' ), OK )
101
102 def test12 ( self ) :
103 statemachine . picture = '+?999.?9?'
104 self . assertEqual ( statemachine . testString ( '-1111' ), OK )
105
106 def test13 ( self ) :
107 statemachine . picture = '+?999.?9?'
108 self . assertEqual ( statemachine . testString ( '-111.11' ), STRINGTOOLONG )
109
110 def test14 ( self ) :
111 statemachine . picture = '+?999.?9?'
112 self . assertEqual ( statemachine . testString ( '+111.1' ), OK )
113
114 def test15 ( self ) :
115 statemachine . picture = '+?999.?9?'
116 self . assertEqual ( statemachine . testString ( '111.1' ), OK )
117
118 def test16 ( self ) :
119 statemachine . picture = '+?999.?9?'
120 self . assertEqual ( statemachine . testString ( '+111.1' ), OK )
121
122 unittest . main ( )
A CareFree State Machine -- Accepts Anything
1 from StateMachine import EBadCharacter, BADCHARACTER, STRINGTOOLONG, OK, StateMachine
2
3 class StateMachine :
4
5 def testString ( self, str ) : return OK
6
7 statemachine = StateMachine ( )
8
9 if __name__ == "__main__" :
10
11 import unittest
12
13 class TestAgainstPostalCodes ( unittest . TestCase ) :
14
15 def test1 ( self ) : self . assertEqual ( statemachine . testString ( 'N0A 1P0' ), OK )
16 def test2 ( self ) : self . assertEqual ( statemachine . testString ( None ), OK )
17 def test3 ( self ) : self . assertEqual ( statemachine . testString ( '' ), OK )
18 def test4 ( self ) : self . assertEqual ( statemachine . testString ( '22' ), OK )
19 def test5 ( self ) : self . assertEqual ( statemachine . testString ( '22x' ), OK )
20 def test6 ( self ) : self . assertEqual ( statemachine . testString ( '2291' ), OK )
21 def test7 ( self ) : self . assertEqual ( statemachine . testString ( '229x' ), OK )
22 def test8 ( self ) : self . assertEqual ( statemachine . testString ( '22999' ), OK )
23
24 unittest . main ( )
Comments
I welcome your comments. - Bill Bell