From 1263460e05d4eac88c51a39cb1e045e2b28891e7 Mon Sep 17 00:00:00 2001 From: corsaronero Date: Fri, 17 Feb 2023 14:14:04 +0000 Subject: [PATCH] first publishing --- parse1.py | 787 +++++++++++++++++++++++++++++++++++++++++++++++++++++ parse1.pyc | Bin 0 -> 9032 bytes 2 files changed, 787 insertions(+) create mode 100644 parse1.py create mode 100644 parse1.pyc diff --git a/parse1.py b/parse1.py new file mode 100644 index 0000000..cb1dfd1 --- /dev/null +++ b/parse1.py @@ -0,0 +1,787 @@ +# Parse wiktionary.xml with pure python, such that it can be run with pypy (python just in time compiler) + + +# optimization would be possible through cython and assembler loops etc + + +# on a linux system, get the first n lines of a document with: + +# head -n1000000 dewiktionary-20181201-pages-articles.xml > wiktionaryFirstMio.xml + + + + + + +import sys +import os + +import re + + + +class Parser(object): + + def __init__(self, InputDokument, OutputDokument): + + self.Indok = InputDokument + self.Outdok = OutputDokument + + + + def GetSeparators(self): + with open(self.Indok) as xmldok: + with open(self.Outdok , 'w') as getsepdok: + seperators = [] + counter = 0 + for line in xmldok: + counter += 1 + #print(counter) + if (counter % 10) == 0: + print(counter) + + seperator =[] + val = 0 + + #if counter == 10000: + #seperatorsSet = [] + #getsepdok.write('[' + '\n') + #for element in seperators: + #seperatorsSet.append(''.join(element)) + + #for element in set(seperatorsSet): + #getsepdok.write(str(''.join(element)) + '\n') + #getsepdok.write(']') + + + for letter in line: + + #print(letter) + if letter == '>': + val = 0 + seperators.append(seperator) + seperator = [] + + if val == 1: + seperator.append(letter) + else: + pass + + if letter == '<': + val = 1 + + seperatorsSet = [] + getsepdok.write('[' + '\n') + for element in seperators: + seperatorsSet.append(''.join(element)) + seperatorsSet = set(seperatorsSet) + for element in set(seperatorsSet): + getsepdok.write(str(''.join(element)) + '\n') + getsepdok.write(']') + return seperatorsSet + + + + def GetPayloadBetweenTwoSymbols(self, SymbolA, SymbolB , LogLineNumber=False, Doc = True): + with open(self.Indok) as xmldok: + with open(self.Outdok , 'w') as payloaddok: + seperators = [] + counter = 0 + valA = 0 + valB = 0 + + seperator =[] + for line in xmldok: + + #print(line) + counter += 1 + + if LogLineNumber == True: + if (counter % 10000) == 0: + print(counter) + + + wait1letterA = False + wait1letterB = False + + + + #for letter in line.decode('utf-8'): + for letter in line: + #print(letter) + #print(set(range(1, len(SymbolA)))) + + + if valA % len(SymbolA) in set(range(1, len(SymbolA) )): + + #print('jo') + if wait1letterA == True: + + #print('joo') + #print(letter) + valA -= valA % len(SymbolA) + + wait1letterA = False + + wait1letterA = True + + + if valB in set(range(1, len(SymbolB) )): + + if wait1letterB == True: + valB = 0 + wait1letterB = False + + wait1letterB = True + + + + + + for n in range(len(SymbolB)): + if valA >= len(SymbolA) and valB == n and letter == SymbolB[n]: + valB = n + 1 + wait1letterB = False + else: + pass + + if valB == len(SymbolB) and valA >= len(SymbolA): + valB = 0 + + #print(letter) + #print(valA) + valA -= len(SymbolA) + #print(valA) + + #print(seperators) + + if valA >= len(SymbolA): + + seperator.append(letter) + + else: + pass + #print(valA) + #print(SymbolA[6]) + #print(len(SymbolA)) + #print(range(len(SymbolA))) + if valA == 0: + + if len(seperator[:-(len(SymbolB)-1)]) >= 1: + + seperators.append(seperator[:-(len(SymbolB)-1)]) + seperator = [] + + for n in range(len(SymbolA)): + #print(n) + if valA % len(SymbolA) == n and letter == SymbolA[n]: + + valA += 1 + #print(valA) + wait1letterA = False + break + else: + pass + + + + seperatorsSet = [] + #getsepdok.write('[' + '\n') + for element in seperators: + seperatorsSet.append(''.join(element)) + seperatorsSet = set(seperatorsSet) + + output = [] + ID = 0 + + ## Set has a probabilistic factor in it!!!! thats why the nmbers change + for element in seperatorsSet: + + output.append([element, ID]) + ID += 1 + + return output + + def GetPayloadBetweenTwoSymbolsInPayload(self, Payload, SymbolA, SymbolB, LogElementNumber): + seperators = [] + counter = 0 + + for element in Payload: + + counter += 1 + + if LogElementNumber == True: + if (counter % 1000) == 0: + print(counter) + + + + seperator =[] + wait1letterA = False + wait1letterB = False + valA = 0 + valB = 0 + + + for letter in element[0]: + #print(letter) + #print(set(range(1, len(SymbolA)))) + if valA % len(SymbolA) in set(range(1, len(SymbolA) )): + #print(valA) + #print('jo') + if wait1letterA == True: + + #print('joo') + + valA -= valA % len(SymbolA) + + wait1letterA = False + + wait1letterA = True + + + if valB in set(range(1, len(SymbolB) )) and valA >= len(SymbolA): + + if wait1letterB == True: + valB = 0 + wait1letterB = False + + wait1letterB = True + + + + + + #for n in range(len(SymbolB)): + #if valB == n and letter == SymbolB[n]: + #valB = n + 1 + #wait1letterB = False + #else: + #pass + + + if letter == SymbolB[valB % len(SymbolB)] and valA >= len(SymbolA): + valB += 1 + wait1letterB = False + else: + pass + + if valB == len(SymbolB) and valA >= len(SymbolA): + valB = 0 + + + #print(valA) + valA -= len(SymbolA) + #print(valA) + + #print(seperators) + + if valA >= len(SymbolA): + ##print(letter) + seperator.append(letter) + #print(seperator) + else: + pass + #print(valA) + #print(SymbolA[6]) + #print(len(SymbolA)) + #print(range(len(SymbolA))) + if valA == 0: + #print('seps') + if len(seperator[:-(len(SymbolB)-1)]) >= 1: + seperators.append([''.join(seperator[:-(len(SymbolB)-1)]), element[1]]) + seperator = [] + + + # Optimierungsmoeglichkeit: Hier kann die for schleife durch viele ifs ersetzt werden, sowas wie start for after zwei ifs. + # wuerde einiges an computation wegnehmen, auch da beide symbole + #for n in range(len(SymbolA)): + ##print(n) + #if valA % len(SymbolA) == n and letter == SymbolA[n]: + ##print(SymbolA[n]) + #valA += 1 + #wait1letterA = False + #else: + #pass + for n in range(len(SymbolA)): + #print(n) + if valA % len(SymbolA) == n and letter == SymbolA[n]: + + valA += 1 + #print(valA) + wait1letterA = False + break + else: + pass + + + + return seperators + + + def GetPayloadBetweenTwoOneSymbolsInPayload(self, Payload, SymbolA, SymbolB, LogElementNumber, Payloadrow, IDrow): + + + + counter = 0 + seperator =[] + + seperators = [] + + for payload in Payload: + val = 0 + for letter in payload[Payloadrow]: + + counter += 1 + #print(counter) + if LogElementNumber == True: + if (counter % 10) == 0: + print(counter) + + #print(letter) + if letter == SymbolB: + val -= 1 + + + if val >= 1: + seperator.append(letter) + + else: + pass + + if val == 0 and len(seperator) >= 1: + + seperators.append([''.join(seperator), payload[IDrow]]) + + seperator = [] + + if letter == SymbolA: + #print(val) + val += 1 + + + return seperators + + def CutTextAtSymbol(self, text, symbol): + itisthesymbol = 0 + outtext = [] + output = [] + symbolisthere = 0 + for letter in text: + + outtext.append(letter) + #print(letter) + if letter != symbol[itisthesymbol]: + itisthesymbol = 0 + if letter == symbol[itisthesymbol]: + itisthesymbol += 1 + + if itisthesymbol == len(symbol): + #print(outtext) + output.append(''.join(outtext)) + itisthesymbol = 0 + symbolisthere = 1 + + if symbolisthere == 0: + output.append(''.join(outtext)) + + + return output[0] + + + def GetPayloadBetweenTwoSymbolsInText(self, text, SymbolA, SymbolB): + seperators = [] + seperator =[] + wait1letterA = False + wait1letterB = False + valA = 0 + valB = 0 + + + for letter in text: + #print(letter) + #print(SymbolA) + if valA % len(SymbolA) in set(range(1, len(SymbolA) )): + + if wait1letterA == True: + + + + valA -= valA % len(SymbolA) + + wait1letterA = False + + wait1letterA = True + #print('B',valB) + #print(valA) + if valB in set(range(1, len(SymbolB) )): + + if wait1letterB == True: + valB = 0 + wait1letterB = False + + wait1letterB = True + + + #print('B',valB) + #print(valA) + + + + if letter == SymbolB[valB % len(SymbolB)]: + valB += 1 + wait1letterB = False + + else: + pass + + if valB == len(SymbolB): + valB = 0 + + + valA -= len(SymbolA) + + + #print('B',valB) + #print(valA) + if valA >= len(SymbolA): + #print('append') + seperator.append(letter) + + + else: + pass + + + + + if valA == 0: + + if len(seperator[:-(len(SymbolB)-1)]) >= 1: + seperators.append([''.join(seperator[:-(len(SymbolB)-1)])]) + seperator = [] + + + # Optimierungsmoeglichkeit: Hier kann die for schleife durch viele ifs ersetzt werden, sowas wie start for after zwei ifs. + # wuerde einiges an computation wegnehmen, auch da beide symbole + #for n in range(len(SymbolA)): + #print(SymbolA[valA % len(SymbolA)]) + if letter == SymbolA[valA % len(SymbolA)]: + #print('oi') + valA += 1 + wait1letterA = False + + else: + pass + + + + return seperators + + def GetPayloadBetweenTwoSameSymbolsInText(self, text, Symbol): + seperators = [] + seperator =[] + wait1letter = False + + nowendit = False + + val = 0 + + + + for letter in text: + #print(letter) + #print(SymbolA) + + if nowendit == False and letter == Symbol[val % len(Symbol)]: + val += 1 + + + if nowendit == True and letter == Symbol[val % len(Symbol)]: + val -= 1 + + + if val == len(Symbol): + seperator.append(letter) + nowendit = True + #print('append') + + if val == 0 and len(seperator) >= 1: + seperators.append(' '.join(seperator)) + seperator = [] + nowendit = False + + return seperators + + def ParseWordswithSymbolFromSymbolongoing(self, text, Symbol): + seperators = [] + #print(text.split()) + for word in text.split(): + + val = 0 + waitoneletter = False + seperator = [] + for letter in word: + + #print(letter) + #print(val) + if val < len(Symbol): + if letter == Symbol[val]: + val += 1 + #print(letter) + #print(len(Symbol)) + #print(val) + if val >= len(Symbol): + val = len(Symbol) + + if val < len(Symbol): + if letter != Symbol[val]: + val = 0 + + if val == len(Symbol): + seperator.append(letter) + #print('itsappending') + + + if len(seperator) >= 1: + seperators.append(''.join(seperator)) + seperator = [] + + return seperators + + def ParseWithHighestLetterAccordance(self, inputtext, Letters): + + # first check if there is a word that has all letters + + short = False + lettervect = [] + Lettervector = [] + + wordscores = [] + + + text = inputtext.lower() + + + if '.' in set(Letters): + short = True + + + + if short == True: + for letter in re.sub("[^a-zA-Züäö.]", " ", Letters): + letter = letter.lower() + #print(re.sub("[^a-züäö.]", " ", Letters)) + + if letter != '.' and letter != ' ': + + lettervect.append(letter) + if letter == '.': + Lettervector.append(lettervect) + lettervect = [] + + if len(lettervect) >= 1: + Lettervector.append(lettervect) + + else: + + + for letter in re.sub("[^a-zA-Züäö.]", " ", Letters): + letter = letter.lower() + Lettervector.append([letter]) + + + #print(text) + #print(Lettervector) + from copy import deepcopy + + for word in text.split(): + + lettervector = deepcopy(Lettervector) + #print(word) + #print(Lettervector) + + wordscore = [] + for n in range(len(lettervector)): + wordscore.append([word, 0]) + + #wordscore = len(lettervector) * [[word, 0 ]] + #print(wordscore) + firstletter = 0 + usedletters = [] + for letter in word: + firstletter += 1 + + + #print(set(Letters)) + #print(wordscore) + + #print(lettervector[n]) + if firstletter == 1: + if letter == lettervector[0][0]: + #print('oi') + #print(lettervector) + #print(len(lettervector[2])) + wordscore[0][1] += 1 + lettervector[0].remove(letter) + #print(usedletters) + else: + lettervector[0].remove(lettervector[0][0]) + + for n in range(len(lettervector)): + + #print('1' ,letter) + #print(lettervector[n][0]) + if letter in set(lettervector[n]): + + #print('ooioi',usedletters) + if letter not in set(usedletters): + #print('something was added', letter) + wordscore[n][1] += 1 + lettervector[n].remove(letter) + #print('angesprungen') + + + + + + wordscores.append(wordscore) + + #print(wordscores) + + #checkbest_firstlettervector = [] + #for n in range(len(wordscores)): + + #checkbest_firstlettervector.append([ n , wordscores[n][0][1]]) + + #print('wordscores', wordscores) + #best_n_lettervectors = sorted(checkbest_firstlettervector[::-1], key=lambda tup: tup[1], reverse=True) + + #print(best_n_lettervectors) + + #for wordscore in wordscores: + ntupelscores = [] + ntupelscoresm = [] + + for o in range(len(wordscores)): + #print('newlettervectorindex') + lastletterexistentindex = 1 + lastlettercame = False + if wordscores[o][0][1] >= 1: + for m in range(1, len(lettervector) + 1): + #print(m) + if o <= len(text.split()) - (m): + + triplescore = [] + for q in range(len(wordscores[o])): + triplescore.append(0) + #print(len(lettervector)) + + + + for n in range(m): + #print(wordscores[lettervectorindex[0] + n][n][1]) + #wordscores[lettervectorindex[0] + 1][1][1] + wordscores[lettervectorindex[0] + 2][2][1] + + for p in range(len(wordscores[o])): + #print(wordscore[o + n][p][1]) + #print(len(Lettervector[p])) + if wordscores[o + n][p][1] == len(Lettervector[p]): + triplescore[p] += wordscores[o + n][p][1] + + letterlength = 0 + for r in range(len(lettervector)): + letterlength += len(Lettervector[r]) + + #print(wordscore) + #print(sum(triplescore)) + + if p == len(wordscores[o]) - 1 and wordscores[o + n][p][1] == len(Lettervector[p]) and lastlettercame == False and sum(triplescore) == letterlength: + #print('oioioioioioioooioioioiiiiiiiiiiiiiiiiiiiiiiiiiii') + lastletterexistentindex = n + lastlettercame = True + + + + + + #triplescore += wordscores[o + n][p][1] + + + ntupelscores.append([[o , m, lastletterexistentindex], sum(triplescore)]) + #ntupelscoresm.append([m , triplescore]) + + + + #print(text.split()) + #print('bliblablub', ntupelscores) + + for tupel in ntupelscores: + + if text.split()[tupel[0][0]][0] == Lettervector[0][0]: + tupel[1] += 3 + + #print('b',text.split()[tupel[0][0] + tupel[0][1] - 1][0]) + #print('a',Lettervector[-1][0]) + if text.split()[tupel[0][0] + tupel[0][1] - 1][0] == Lettervector[-1][0]: + tupel[1] += 3 + + + # Bestrafe laengere Tupel, sprich wenn durch weitere worte kein score dazukommt + tupel[1] -= tupel[0][1] * 0.1 + + bestntupelscoresorted = sorted(ntupelscores[::-1], key=lambda tup: tup[1], reverse=True) + #bestntupelscoresortedm = sorted(ntupelscoresm[::-1], key=lambda tup: tup[1], reverse=True) + + #print('oioioioioioioioioioi',bestntupelscoresorted) + outputntupel = [] + + + + + + #print(bestntupelscoresorted) + for s in range(bestntupelscoresorted[0][0][1] ): + + outputntupel.append(text.split()[bestntupelscoresorted[0][0][0] + s]) + + #print(outputntupel) + + return outputntupel + + + #def parseWordsContainingCertainSymbols(self, text, symbols): + #print() + + + + + +#fooSeparator = 'title' + +#cwd = os.getcwd() + +#with open('dewiktionary-20181201-pages-articles.xml') as xmldok: + #with open(cwd + '/' + 'classes.txt', 'w') as Outdok: + #n = 0 + #done = False + #while done == False: + #for line in xmldok: + #n += 1 + ##print(line) + ##print(dok_to_token(line)) + ##print(n) + #for word in line: + #print(word) + + #try: + #if dok_to_token(line)[:(len(fooSeparator) + 2)] == '<' + fooSeparator + '>': + #Outdok.write(dok_to_token(line)[len(fooSeperator):-len(fooSeperator)] + '\n') + #except: + #pass + #if n >= 100000: + #quit() + + + + diff --git a/parse1.pyc b/parse1.pyc new file mode 100644 index 0000000000000000000000000000000000000000..c82b1489ac4ab9a0f722ed0e9d1a486a3e637287 GIT binary patch literal 9032 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