169 lines
5.6 KiB
Python
169 lines
5.6 KiB
Python
import functools
|
||
|
||
|
||
class Edge:
|
||
# 符号 开始状态 结束状态
|
||
def __init__(self, label: chr, start: int, end: int):
|
||
self.label = label
|
||
self.start = start
|
||
self.end = end
|
||
|
||
|
||
class EdgeGroup:
|
||
def __init__(self, start: int, end: int, numOfState: int, edges: list[Edge]):
|
||
self.edges = edges
|
||
self.start = start
|
||
self.end = end
|
||
self.numOfState = numOfState
|
||
|
||
def append(self, edges: list[Edge]):
|
||
self.edges += edges
|
||
|
||
|
||
class NFA:
|
||
# ( ) | * . others
|
||
# priority * . |
|
||
|
||
def Priority(self, a: chr, b: chr) -> int: # a > b 1 ,a == b 0 ,a < b -1
|
||
if a == b:
|
||
return 0
|
||
pri = ['|', '.', '*', '(']
|
||
return 1 if pri.index(a) > pri.index(b) else -1
|
||
|
||
def EdgePriority(self, a: Edge, b: Edge) -> int:
|
||
a = a.label
|
||
b = b.label
|
||
if a == '~':
|
||
return -1
|
||
if b == '~':
|
||
return 1
|
||
return 1 if ord(b) < ord(a) else -1
|
||
|
||
def AddConcat(self, s: str) -> str:
|
||
lt = list(s)
|
||
i = 0
|
||
while i < len(lt):
|
||
if lt[i] in '|.(':
|
||
pass
|
||
elif i + 1 < len(lt) and (lt[i + 1].isalpha() or lt[i + 1] == '('):
|
||
lt.insert(i + 1, '.')
|
||
i += 1
|
||
return ''.join(lt)
|
||
|
||
def ToPostfix(self, s: str) -> str:
|
||
tempSt = []
|
||
operSt = []
|
||
for c in s:
|
||
match c:
|
||
case '(':
|
||
operSt.append(c)
|
||
case ')':
|
||
while operSt[-1] != '(':
|
||
tempSt.append(operSt.pop())
|
||
operSt.pop()
|
||
case '*' | '|' | '.':
|
||
if len(operSt) == 0 or operSt[-1] == '(':
|
||
operSt.append(c)
|
||
else:
|
||
while len(operSt) != 0 and self.Priority(c, operSt[-1]) != 1:
|
||
tempSt.append(operSt.pop())
|
||
operSt.append(c)
|
||
case _:
|
||
tempSt.append(c)
|
||
while len(operSt) != 0:
|
||
tempSt.append(operSt.pop())
|
||
return ''.join(tempSt)
|
||
|
||
def ToNFA(self, s: str) -> EdgeGroup:
|
||
stack = []
|
||
for c in s:
|
||
match c:
|
||
case '|':
|
||
edgeGroups = stack[-2:]
|
||
stack = stack[:-2]
|
||
eg = EdgeGroup(0, edgeGroups[0].numOfState + edgeGroups[1].numOfState - 3,
|
||
edgeGroups[0].numOfState + edgeGroups[1].numOfState - 2, [])
|
||
for edge in edgeGroups[0].edges:
|
||
if edgeGroups[0].end == edge.end:
|
||
edge.end = eg.end
|
||
eg.append([edge])
|
||
for edge in edgeGroups[1].edges:
|
||
if edgeGroups[1].end == edge.end:
|
||
edge.end = eg.end
|
||
else:
|
||
edge.end += edgeGroups[0].numOfState - 2
|
||
edge.start += edgeGroups[0].numOfState - 2 if edge.start != 0 else 0
|
||
eg.append([edge])
|
||
stack.append(eg)
|
||
case '.':
|
||
edgeGroups = stack[-2:]
|
||
stack = stack[:-2]
|
||
eg = EdgeGroup(0, edgeGroups[0].numOfState + edgeGroups[1].numOfState - 2,
|
||
edgeGroups[0].numOfState + edgeGroups[1].numOfState - 1, edgeGroups[0].edges)
|
||
for edge in edgeGroups[1].edges:
|
||
edge.start += edgeGroups[0].numOfState - 1
|
||
edge.end += edgeGroups[0].numOfState - 1
|
||
eg.append([edge])
|
||
stack.append(eg)
|
||
case '*':
|
||
edgeGroup = stack[-1]
|
||
stack.pop()
|
||
eg = EdgeGroup(0, edgeGroup.numOfState, edgeGroup.numOfState + 1, [])
|
||
for edge in edgeGroup.edges:
|
||
edge.start += 1
|
||
edge.end = edgeGroup.start+1 if edge.end == edgeGroup.end else edge.end + 1
|
||
eg.append([edge])
|
||
eg.append([Edge('~', 0, 1), Edge('~', 1, eg.end)])
|
||
stack.append(eg)
|
||
case _:
|
||
stack.append(EdgeGroup(0, 1, 2, [Edge(c, 0, 1)]))
|
||
return stack[0]
|
||
|
||
def printEdge(self, eg: Edge, st: str = '', ed: str = '') -> None:
|
||
# 0‐~‐>1
|
||
print(eg.start - 1 if st == '' else st, '-', eg.label, '->', eg.end - 1 if ed == '' else ed, sep='', end=' ')
|
||
|
||
def printNFA(self, eg: EdgeGroup) -> None:
|
||
dt = {}
|
||
for edge in eg.edges:
|
||
if edge.start in dt:
|
||
dt[edge.start].append(edge)
|
||
else:
|
||
dt[edge.start] = [edge]
|
||
i = 0
|
||
while i in dt:
|
||
edges = dt[i]
|
||
edges.sort(key=functools.cmp_to_key(self.EdgePriority))
|
||
if i == 0:
|
||
print('X', end=' ')
|
||
for edge in edges:
|
||
self.printEdge(edge, st='X')
|
||
print('\nY')
|
||
i += 1
|
||
continue
|
||
print(i - 1, end=' ')
|
||
if i + 1 not in dt:
|
||
for edge in edges:
|
||
self.printEdge(edge, ed='Y')
|
||
else:
|
||
for edge in edges:
|
||
self.printEdge(edge)
|
||
print()
|
||
i += 1
|
||
pass
|
||
|
||
def f(self, s: str) -> None:
|
||
s = self.AddConcat(s)
|
||
print(s)
|
||
s = self.ToPostfix(s)
|
||
print(s)
|
||
s = self.ToNFA(s)
|
||
self.printNFA(s)
|
||
|
||
|
||
nfa = NFA()
|
||
nfa.f("(a|b)*baa")
|
||
nfa.f(input().lower())
|
||
|
||
# print(nfa.AddConcat("(a*b)k"))
|