2015-05-03 15 views
5

tôi có mã này trong tập tin C của tôi:Làm cách nào để phân tích cú pháp chuỗi định dạng C bằng Python?

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

tôi muốn, với Python, để có thể phân tích các chuỗi định dạng và xác định vị trí "%s""%d".

Vì vậy, tôi muốn có một hàm:

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

tôi đã cố gắng để đạt được bindings Python này sử dụng libclang, và với pycparser, nhưng tôi không thấy thế nào điều này có thể được thực hiện với những công cụ này.

Tôi cũng đã thử sử dụng regex để giải quyết vấn đề này, nhưng điều này không đơn giản chút nào - hãy suy nghĩ về các trường hợp sử dụng khi printf"%%s" và các nội dung tương tự.

Cả gcc và clang rõ ràng làm điều này như là một phần của quá trình biên dịch - không có ai xuất logic này sang Python không?

+0

Tất cả tôi muốn để làm, chỉ đơn giản là để lo cate "% d" và "% s" bên trong chuỗi - để biết chỉ mục của chúng nếu bạn muốn, và không chuyển đổi nó thành một bản in Python – speller

+0

bạn không thể dễ dàng phân tích nó bằng một regex đơn giản, bạn cần xử lý char bằng char . –

+0

Điều này tất nhiên là có thể, nhưng không đơn giản, tôi thà tránh nó. Thật lạ khi logic này nằm bên trong gcc và clang, không có sẵn trong Python, cũng trong thư viện phân tích cú pháp c – speller

Trả lời

3

Bạn có thể chắc chắn tìm thấy các ứng cử viên được định dạng đúng với một regex .

Hãy xem định nghĩa của C Format Specification. (. Sử dụng Microsofts, nhưng sử dụng những gì bạn muốn)

Đó là:

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

Bạn cũng có trường hợp đặc biệt của %% mà trở nên % trong printf.

Bạn có thể dịch mô hình đó vào một regex:

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

Và sau đó vào một regex 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))) 

Prints:

"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

Một thực hiện đơn giản có thể là máy phát điện sau:

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

Điều này có thể khá dễ dàng mở rộng để xử lý thêm thông tin format specifier như chiều rộng và chính xác, nếu cần thiết.

+0

Kỳ lạ đủ '"% -0.3% "' là một định dạng hợp lệ (có nghĩa là '"% "' và không sử dụng bất kỳ đối số nào) – 6502

+1

Vâng, như đã đề cập câu trả lời của tôi không xử lý bất kỳ chỉnh sửa thêm nào giữa '%' hàng đầu và các loại specifier vì OP đã không yêu cầu cho điều đó. –

+0

Xin lỗi vì tiếng ồn ... tôi nhận ra rằng OP đang hỏi về chuỗi định dạng C, không phải chuỗi định dạng kiểu cũ của Python – 6502

0

đây là một mã lặp đi lặp lại tôi đã viết rằng in các chỉ số của% s% d hoặc bất kỳ chuỗi định dạng như

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

hy vọng nó sẽ giúp

+0

Cảm ơn bạn! Đó là một khởi đầu tuyệt vời cho tôi, mặc dù nó không bao gồm tất cả các trường hợp - chẳng hạn như% * d và các nội dung tương tự – speller

Các vấn đề liên quan