2015-05-03 16 views
5

Ich habe diesen Code in meiner C-Datei:Wie kann ich eine C-Formatzeichenfolge in Python analysieren?

printf("Worker name is %s and id is %d", worker.name, worker.id); 

ich will, mit Python, der Lage sein, das Format Zeichenfolge zu analysieren und die "%s" und "%d" zu finden.

Deshalb möchte ich eine Funktion haben:

>>> my_function("Worker name is %s and id is %d") 
[Out1]: ((15, "%s"), (28, "%d)) 

Ich habe versucht, dies mit libclang der Python-Anbindung zu erreichen, und mit pycparser, aber ich sah nicht, wie kann dies mit diesen Werkzeugen durchgeführt werden.

Ich habe auch versucht mit Regex, um das zu lösen, aber das ist überhaupt nicht einfach - über Anwendungsfälle denken, wenn die printf hat "%%s" und solche Sachen.

Sowohl gcc als auch clang machen das offensichtlich als Teil des Kompilierens - hat niemand diese Logik nach Python exportiert?

+0

Alles, was ich will zu tun, ist einfach zu lo Cate die "% d" und "% s" innerhalb der Zeichenfolge - zu wissen, ihre Indizes, wenn Sie, und nicht dies in eine Python drucken – speller

+0

konvertieren Sie können es nicht einfach mit einem einfachen Regex parsen, müssen Sie mit char durch char umgehen . –

+0

Das ist natürlich möglich, aber nicht einfach, ich werde es eher vermeiden. Es ist seltsam, dass diese Logik, die innerhalb von GCC und CLAMG liegt, in Python nicht verfügbar ist, auch in Parsing-Bibliotheken – speller

Antwort

3

Sie druckt kann sicherlich richtig formatiert Kandidaten mit einem regulären Ausdruck finden .

Werfen Sie einen Blick auf die Definition der C Format Specification. (. Mit Microsofts, aber verwenden, was Sie wollen)

Es ist:

%[flags] [width] [.precision] [{h | l | ll | w | I | I32 | I64}] type 

Sie haben auch den Sonderfall %% die % in printf wird.

Sie können dieses Muster in eine regex übersetzen:

(        # start of capture group 1 
%         # literal "%" 
(?:        # first option 
(?:[-+0 #]{0,5})     # optional flags 
(?:\d+|\*)?      # width 
(?:\.(?:\d+|\*))?     # precision 
(?:h|l|ll|w|I|I32|I64)?   # size 
[cCdiouxXeEfgGaAnpsSZ]   # type 
) |        # OR 
%%)        # literal "%%" 

Demo

und dann in eine Python Regex:

import re 

lines='''\ 
Worker name is %s and id is %d 
That is %i%% 
%c 
Decimal: %d Justified: %.6d 
%10c%5hc%5C%5lc 
The temp is %.*f 
%ss%lii 
%*.*s | %.3d | %lC | %s%%%02d''' 

cfmt='''\ 
(         # start of capture group 1 
%         # literal "%" 
(?:        # first option 
(?:[-+0 #]{0,5})     # optional flags 
(?:\d+|\*)?      # width 
(?:\.(?:\d+|\*))?     # precision 
(?:h|l|ll|w|I|I32|I64)?   # size 
[cCdiouxXeEfgGaAnpsSZ]    # type 
) |        # OR 
%%)        # literal "%%" 
''' 

for line in lines.splitlines(): 
    print '"{}"\n\t{}\n'.format(line, 
      tuple((m.start(1), m.group(1)) for m in re.finditer(cfmt, line, flags=re.X))) 

Drucke:

"Worker name is %s and id is %d" 
    ((15, '%s'), (28, '%d')) 

"That is %i%%" 
    ((8, '%i'), (10, '%%')) 

"%c" 
    ((0, '%c'),) 

"Decimal: %d Justified: %.6d" 
    ((9, '%d'), (24, '%.6d')) 

"%10c%5hc%5C%5lc" 
    ((0, '%10c'), (4, '%5hc'), (8, '%5C'), (11, '%5lc')) 

"The temp is %.*f" 
    ((12, '%.*f'),) 

"%ss%lii" 
    ((0, '%s'), (3, '%li')) 

"%*.*s | %.3d | %lC | %s%%%02d" 
    ((0, '%*.*s'), (8, '%.3d'), (15, '%lC'), (21, '%s'), (23, '%%'), (25, '%02d')) 
1

Eine einfache Implementierung könnte der folgende Generator sein:

def find_format_specifiers(s): 
    last_percent = False 
    for i in range(len(s)): 
     if s[i] == "%" and not last_percent: 
      if s[i+1] != "%": 
       yield (i, s[i:i+2]) 
      last_percent = True 
     else: 
      last_percent = False 

>>> list(find_format_specifiers("Worker name is %s and id is %d but %%q")) 
[(15, '%s'), (28, '%d')] 

Dies kann erweitert ziemlich leicht sein, zusätzliche Formatspezifizierer Informationen wie Breite und Genauigkeit zu handhaben, wenn nötig.

+0

Seltsamerweise '"% -0.3% "' ist ein gültiger Formatbezeichner (bedeutet "%" und verwendet kein Argument) – 6502

+1

Ja, wie gesagt, meine Antwort behandelt keine zusätzliche Verschönerung zwischen den führenden '%' und der Typspezifizierer, weil das OP nicht darum gebeten hat. –

+0

Sorry für das Rauschen ... ich erkannte jetzt, dass das OP nach C-Formatierungszeichenfolgen fragt, nicht nach Python-Formatierungszeichenfolgen im alten Stil – 6502

0

dies ist ein iterativer Code habe ich geschrieben, dass die Indizes von% s% d oder eine solche Formatstring

  import re 
      def myfunc(str): 
       match = re.search('\(.*?\)',str) 
       if match: 
        new_str = match.group() 
        new_str = new_str.translate(None,''.join(['(',')','"'])) #replace the characters in list with none 
        print new_str 
        parse(new_str) 
       else: 
        print "No match" 

      def parse(str): 
       try: 
        g = str.index('%') 
        print " %",str[g+1]," = ",g 
        #replace % with ' ' 
        list1 = list(str) 
        list1[str.index('%')] = ' ' 
        str = ''.join(list1) 

        parse(str) 
       except ValueError,e: 
        return 

      str = raw_input() 
      myfunc(str)` 

hoffe, es hilft

+0

Vielen Dank! Es ist ein guter Anfang für mich, obwohl es nicht alle Fälle deckt - wie% * d und solche Sachen – speller

Verwandte Themen