2013-02-16 20 views
5

Thư viện chuẩn của nhiều ngôn ngữ lập trình bao gồm "API trình quét" để trích xuất chuỗi, số hoặc các đối tượng khác từ luồng nhập văn bản. (Ví dụ: Java bao gồm lớp Scanner, C++ bao gồm istream và C bao gồm scanf).Trích xuất luồng Python

Tương đương với điều này bằng Python là gì?

Python có giao diện luồng, tức là các lớp kế thừa từ io.IOBase. Tuy nhiên, giao diện luồng Python TextIOBase chỉ cung cấp các phương tiện cho đầu vào định hướng dòng. Sau reading the documentationsearching on Google, tôi không thể tìm thấy nội dung nào đó trong các mô-đun Python chuẩn sẽ cho phép tôi, ví dụ trích xuất một số nguyên từ luồng văn bản hoặc trích xuất từ ​​được phân cách bằng dấu cách. Có bất kỳ cơ sở tiêu chuẩn nào để thực hiện việc này không?

+0

Nếu đầu vào rất bẩn/tùy ý, tôi có xu hướng sử dụng mô đun 're'; nếu đầu vào được cấu trúc, tôi thích một thư viện phân tích cú pháp như simpleparse (EBNL dễ bảo trì hơn các biểu thức thông thường). –

+1

Nếu bạn có một trường hợp sử dụng trong tâm trí, có lẽ nó sẽ có hiệu quả hơn để cập nhật câu hỏi của bạn thay vì thực hiện một yêu cầu chung chung. –

+0

Xem http://stackoverflow.com/questions/2175080/sscanf-in-python để biết một số đề xuất khác. –

Trả lời

3

Không có tương đương fscanf hoặc Java Scanner. Giải pháp đơn giản nhất là yêu cầu người dùng sử dụng đầu vào phân tách dòng mới thay vì đầu vào được phân tách bằng dấu cách, sau đó bạn có thể đọc từng dòng và chuyển đổi các dòng thành loại chính xác.

Nếu bạn muốn người dùng cung cấp đầu vào có cấu trúc hơn thì có thể bạn nên tạo trình phân tích cú pháp cho đầu vào của người dùng. Có một số thư viện phân tích cú pháp đẹp cho python, ví dụ: pyparsing. Cũng có một mô-đun scanf, mặc dù bản cập nhật cuối cùng là năm 2008.

Nếu bạn không muốn có phụ thuộc bên ngoài thì bạn có thể sử dụng regexes để khớp với chuỗi đầu vào. Chắc chắn regexes yêu cầu để làm việc trên dây, nhưng bạn có thể dễ dàng vượt qua giới hạn này đọc trong khối. Ví dụ một cái gì đó như thế này nên làm việc tốt hầu hết thời gian:

import re 


FORMATS_TYPES = { 
    'd': int, 
    'f': float, 
    's': str, 
} 


FORMATS_REGEXES = {  
    'd': re.compile(r'(?:\s|\b)*([+-]?\d+)(?:\s|\b)*'), 
    'f': re.compile(r'(?:\s|\b)*([+-]?\d+\.?\d*)(?:\s|\b)*'), 
    's': re.compile(r'\b(\w+)\b'), 
} 


FORMAT_FIELD_REGEX = re.compile(r'%(s|d|f)') 


def scan_input(format_string, stream, max_size=float('+inf'), chunk_size=1024): 
    """Scan an input stream and retrieve formatted input.""" 

    chunk = '' 
    format_fields = format_string.split()[::-1] 
    while format_fields: 
     fields = FORMAT_FIELD_REGEX.findall(format_fields.pop()) 
     if not chunk: 
      chunk = _get_chunk(stream, chunk_size) 

     for field in fields: 
      field_regex = FORMATS_REGEXES[field] 
      match = field_regex.search(chunk) 
      length_before = len(chunk) 
      while match is None or match.end() >= len(chunk): 
       chunk += _get_chunk(stream, chunk_size) 
       if not chunk or length_before == len(chunk): 
        if match is None: 
         raise ValueError('Missing fields.') 
        break 
      text = match.group(1) 
      yield FORMATS_TYPES[field](text) 
      chunk = chunk[match.end():] 



def _get_chunk(stream, chunk_size): 
    try: 
     return stream.read(chunk_size) 
    except EOFError: 
     return '' 

sử dụng Ví dụ:

>>> s = StringIO('1234 Hello World -13.48 -678 12.45') 
>>> for data in scan_input('%d %s %s %f %d %f', s): print repr(data) 
...                        
1234                       
'Hello' 
'World' 
-13.48 
-678 
12.45 

Bạn có lẽ sẽ phải mở rộng này, và thử nghiệm nó đúng nhưng nó sẽ cho bạn một số ý tưởng .

1

Không có tương đương trực tiếp (theo như tôi biết). Tuy nhiên, bạn có thể thực hiện khá nhiều điều tương tự với các biểu thức thông thường (xem mô-đun re).

Ví dụ:

# matching first integer (space delimited) 
re.match(r'\b(\d+)\b',string) 

# matching first space delimited word 
re.match(r'\b(\w+)\b',string) 

# matching a word followed by an integer (space delimited) 
re.match(r'\b(\w+)\s+(\d+)\b',string) 

Nó đòi hỏi một công việc ít hơn so với giao diện máy quét C-phong cách bình thường, nhưng nó cũng rất linh hoạt và mạnh mẽ. Tuy nhiên, bạn sẽ phải xử lý luồng I/O.