2015-05-03 1 views
5

Ho questo codice nel mio file C:Come posso analizzare una stringa in formato C in Python?

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

che voglio, con Python, per essere in grado di analizzare la stringa di formato e individuare il "%s" e "%d".

Quindi voglio avere una funzione:

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

ho cercato di raggiungere binding Python questo usando del libclang, e con pycparser, ma non ho visto come si può fare con questi strumenti.

Ho anche provato a usare regex per risolvere questo problema, ma questo non è affatto semplice - pensate ai casi d'uso quando lo printf ha "%%s" e cose del genere.

Sia gcc che clang lo fanno ovviamente come parte della compilazione - nessuno ha esportato questa logica in Python?

+0

Tutto quello che voglio fare, è semplicemente per lo cate "% d" e "% s" all'interno della stringa - per conoscere i loro indici se volete, e non per convertirli in una stampa Python – speller

+0

non potete facilmente analizzarli con una semplice regex, dovete gestire char per char . –

+0

Questo è ovviamente possibile, ma non semplice, preferisco evitarlo. È strano che questa logica, che è all'interno di gcc e clang, non sia disponibile in Python, anche nelle librerie di parsing – speller

risposta

3

Si può certamente trovare candidati correttamente formattati con una regex .

Dai un'occhiata alla definizione di C Format Specification. (. Utilizzando Microsofts, ma utilizzare ciò che si vuole)

E ':

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

hai anche il caso particolare della %% che diventa % in printf.

È possibile tradurre quel modello in un'espressione regolare:

(        # 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

e poi in una regex di Python:

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))) 

Stampe:

"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

Una semplice implementazione potrebbe essere il seguente generatore:

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')] 

Questo può essere abbastanza facilmente esteso per gestire ulteriori informazioni di formato come larghezza e precisione, se necessario.

+0

Stranamente '"% -0.3% "' è un identificatore di formato valido (che significa '"% "' e non usa alcun argomento) – 6502

+1

Sì, come già detto la mia risposta non gestisce nessun abbellimento extra tra il principale '%' e lo specificatore del tipo perché l'OP non lo chiedeva. –

+0

Scusate per il rumore ... mi sono reso conto ora che l'OP sta chiedendo delle stringhe di formattazione C, non delle stringhe di formattazione vecchio stile Python – 6502

0

questo è un codice iterativo ho scritto che stampa gli indici di% s% d o qualsiasi stringa di formato

  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)` 

Speranza che aiuta

+0

Grazie! È un ottimo inizio per me, anche se non copre tutti i casi, come% * d e cose del genere – speller