2011-08-24 5 views
9

은 내가 쉼표새 행을 삽입하지 않고 사용자 입력을받을 수 있습니까?

print "Hello, world!", 

를 추가하여 줄 바꿈을 쓰는 인쇄를 중지 할 수 있습니다 알고하지만 줄 바꿈을 쓰는 raw_input을 어떻게 중지합니까?

print "Hello, ", 
name = raw_input() 
print ", how do you do?" 

결과 :

안녕하세요, 토마스
, 어떻게해야합니까?

결과는 내가 원하는 :

안녕하세요, 토마스, 당신은 어떻게해야합니까?

+0

'raw_input'의 개행 문자가 사용자가 리턴 키를 클릭 한 것이기 때문에 내가 예상 한 것입니다. 그래도 여전히 피할 수있는 방법이 필요합니다. :-) – Hubro

+2

첫 번째 결과는 "안녕하세요, Tomas
Tomas, 어떻게 하시겠습니까?" ;) – Jacob

+0

나는 – Hubro

답변

6

그러나 raw_input이 개행을 쓰지 않게하려면 어떻게해야합니까?

간단히 : 당신은 할 수 없습니다.

raw_input()은 항상 마지막 줄 바꿈을 포함하여 사용자가 입력 한 텍스트를 표시합니다. 즉, 사용자가 입력하는 내용이 표준 출력에 인쇄됩니다.

이 문제를 방지하려면 curses 모듈과 같은 터미널 제어 라이브러리를 사용해야합니다. 예를 들어 curses은 Windows 시스템에서 사용할 수 없습니다.

+0

'raw_input()'은 자신의 docstring에 따라 후행 줄 바꿈을 제거합니다. – Wieland

+1

@Wieland H .:하지만 여전히 ** echo ** it, 예. 표준 출력에 기록하십시오. 이것이 내가 말한 전부입니다. 반환 값은 줄 바꿈이 제거되지만이 질문과는 관련이 없습니다. 투표하기 전에 읽어보십시오. –

0

getpass.getpass()는 원하는 것을 수행합니까?

+0

좋은 제안처럼 보입니다. 불행히도'getpass'는 개행 문자를 출력합니다. –

7

이 다소 그것을 우회하지만, 변수 name에 아무것도 지정하지 않습니다

print("Hello, {0}, how do you do?".format(raw_input("Enter name here: "))) 

그것은 비록 전체 메시지를 인쇄하기 전에 사용자에게 이름을 묻는 메시지가 표시됩니다.

6

나는 아무도 작동하는 해결책을 제시하지 않았 음을 알았 기 때문에 나는 그것을 줄 것이라고 결심했다. Ferdinand Beyer에 따르면 사용자 입력 후 raw_input()에 새 줄을 인쇄하지 못하게하는 것은 불가능합니다. 그러나 이전 회선으로 돌아갈 수 있습니다. 한 줄로 만들었습니다. 당신은 사용할 수 있습니다 : x 지정된 사용자 입력 및 yraw_input()의 문자열의 길이의 정수의 길이의 정수이다

print '\033[{}C\033[1A'.format(len(x) + y), 

. 모든 터미널에서 작동하지 않을 수도 있지만 (이 방법에 대해 배웠을 때 읽었던 것처럼), 제 문제는 제대로 작동합니다. 나는 쿠분투 14.04를 사용하고있다.
'\033[4C' 문자열은 오른쪽에 4 개의 인덱스를 점프하는 데 사용되므로 ' ' * 4과 같습니다. 같은 방법으로 문자열 '\033[1A'을 사용하여 1 행 위로 이동합니다. 문자열의 마지막 색인에 A, B, C 또는 D 문자를 사용하면 위, 아래, 오른쪽 및 왼쪽으로 각각 이동할 수 있습니다.

줄이 있으면 그 자리에있는 기존의 인쇄 된 문자가 삭제됩니다.

+0

이것은 훌륭합니다, 감사합니다! – Matt

1

Nick K.이 말했듯이, 개행 문자가 반향되기 전에 텍스트 커서를 다시 이동시켜야합니다. 문제는 오른쪽으로 이동하기 위해 이전 줄의 길이를 쉽게 얻을 수 없다는 것입니다. 인쇄 된 모든 문자열을 저장하고 프롬프트에 입력 한 다음 자체 변수에 입력하지 않도록해야합니다.

다음은 터미널에서 마지막 줄을 자동으로 저장하여 (이 방법을 사용하는 경우)이를 수정하는 클래스입니다 (Python 3). 이것의 장점은 터미널 컨트롤 라이브러리를 사용하는 것과 비교하여 최신 버전의 Windows와 * NIX 운영 체제 모두에서 표준 터미널에서 작동한다는 것입니다. 또한 입력을 시작하기 전에 'Hello'프롬프트가 출력됩니다.

Windows에 있지만 Windows 10의 v1511이 아닌 경우 colorama 모듈을 설치해야합니다. 그렇지 않으면 해당 버전에서 ANSI 커서 이동 기능이 지원되어 작동하지 않습니다.

# For the sys.stdout file-like object 
import sys 
import platform 

if platform.system() == 'Windows': 
    try: 
     import colorama 
    except ImportError: 
     import ctypes 
     kernel32 = ctypes.windll.kernel32 
     # Enable ANSI support on Windows 10 v1511 
     kernel32.SetConsoleMode(kernel32.GetStdHandle(-11), 7) 
    else: 
     colorama.init() 
else: 
    # Fix Linux arrow key support in Python scripts 
    import readline 


class TempHistory: 
    """Record one line from the terminal. 

    It is necessary to keep track of the last line on the terminal so we 
    can move the text cursor rightward and upward back into the position 
    before the newline from the `input` function was echoed. 

    Note: I use the term 'echo' to refer to when text is 
    shown on the terminal but might not be written to `sys.stdout`. 

    """ 

    def __init__(self): 
     """Initialise `line` and save the `print` and `input` functions. 

     `line` is initially set to '\n' so that the `record` method 
     doesn't raise an error about the string index being out of range. 

     """ 
     self.line = '\n' 
     self.builtin_print = print 
     self.builtin_input = input 

    def _record(self, text): 
     """Append to `line` or overwrite it if it has ended.""" 
     if text == '': 
      # You can't record nothing 
      return 
     # Take into account `text` being multiple lines 
     lines = text.split('\n') 
     if text[-1] == '\n': 
      last_line = lines[-2] + '\n' 
      # If `text` ended with a newline, then `text.split('\n')[-1]` 
      # would have merely returned the newline, and not the text 
      # preceding it 
     else: 
      last_line = lines[-1] 
     # Take into account return characters which overwrite the line 
     last_line = last_line.split('\r')[-1] 
     # `line` is considered ended if it ends with a newline character 
     if self.line[-1] == '\n': 
      self.line = last_line 
     else: 
      self.line += last_line 

    def _undo_newline(self): 
     """Move text cursor back to its position before echoing newline. 

     ANSI escape sequence: `\x1b[{count}{command}` 
     `\x1b` is the escape code, and commands `A`, `B`, `C` and `D` are 
     for moving the text cursor up, down, forward and backward {count} 
     times respectively. 

     Thus, after having echoed a newline, the final statement tells 
     the terminal to move the text cursor forward to be inline with 
     the end of the previous line, and then move up into said line 
     (making it the current line again). 

     """ 
     line_length = len(self.line) 
     # Take into account (multiple) backspaces which would 
     # otherwise artificially increase `line_length` 
     for i, char in enumerate(self.line[1:]): 
      if char == '\b' and self.line[i-1] != '\b': 
       line_length -= 2 
     self.print('\x1b[{}C\x1b[1A'.format(line_length), 
        end='', flush=True, record=False) 

    def print(self, *args, sep=' ', end='\n', file=sys.stdout, flush=False, 
       record=True): 
     """Print to `file` and record the printed text. 

     Other than recording the printed text, it behaves exactly like 
     the built-in `print` function. 

     """ 
     self.builtin_print(*args, sep=sep, end=end, file=file, flush=flush) 
     if record: 
      text = sep.join([str(arg) for arg in args]) + end 
      self._record(text) 

    def input(self, prompt='', newline=True, record=True): 
     """Return one line of user input and record the echoed text. 

     Other than storing the echoed text and optionally stripping the 
     echoed newline, it behaves exactly like the built-in `input` 
     function. 

     """ 
     if prompt == '': 
      # Prevent arrow key overwriting previously printed text by 
      # ensuring the built-in `input` function's `prompt` argument 
      # isn't empty 
      prompt = ' \b' 
     response = self.builtin_input(prompt) 
     if record: 
      self._record(prompt) 
      self._record(response) 
     if not newline: 
      self._undo_newline() 
     return response 


record = TempHistory() 
# For convenience 
print = record.print 
input = record.input 

print('Hello, ', end='', flush=True) 
name = input(newline=False) 
print(', how do you do?) 
0

자신의 함수를 정의하는 줄 바꿈을 역 추적하는 또 다른 방법이 에뮬레이트도 동안, 반향과 (응답을 반환합니다)를 입력 제외 response 변수에 모든 키 입력을 추가, 내장에 input 기능 백 스페이스 처리, , 클립 보드 , , 화살표 키, 선 역사, KeyboardInterrupt, 참고 EOFError, SIGTSTP 및 붙여 넣기. 매우입니다.

일반적인 경우 input과 같은 화살표 키를 사용하여 회선 기록을 사용하려면 Windows의 경우 pyreadline을 설치해야합니다. 그래도 기능이 여전히 적합하지는 않으므로 불완전합니다. 또한 v1511 이상의 Windows 10을 사용하고 있지 않다면 colorama 모듈을 설치해야합니다 (Linux 또는 macOS를 사용하는 경우에는 아무 것도 할 필요가 없습니다).

또한 '\ xe0'을 사용하여 특수 문자를 나타내는 msvcrt.getwch으로 인해 'à'을 (를) 입력 할 수 없습니다. 너 그래도 붙여 넣을 수 있어야합니다.

다음은이 작업을 Windows 10 시스템 (최소 v1511), Debian 기반 Linux 배포판 및 macOS 및 기타 * NIX 운영 체제로 변경하는 코드입니다. Windows에 pyreadline이 설치되어 있는지 여부에 관계없이 작동해야하지만 일부 기능이 부족합니다.

windows_specific.py 물 :

"""Windows-specific functions and variables for input_no_newline.""" 
import ctypes 
from msvcrt import getwch # pylint: disable=import-error, unused-import 
from shared_stuff import ANSI 

try: 
    import colorama # pylint: disable=import-error 
except ImportError: 
    kernel32 = ctypes.windll.kernel32 
    # Enable ANSI support to move the text cursor 
    kernel32.SetConsoleMode(kernel32.GetStdHandle(-11), 7) 
else: 
    colorama.init() 


def get_clipboard_data(): 
    """Return string previously copied from Windows clipboard. 

    Adapted from <http://stackoverflow.com/a/23285159/6379747>. 

    """ 
    CF_TEXT = 1 
    user32 = ctypes.windll.user32 
    user32.OpenClipboard(0) 
    try: 
     if user32.IsClipboardFormatAvailable(CF_TEXT): 
      data = user32.GetClipboardData(CF_TEXT) 
      data_locked = kernel32.GlobalLock(data) 
      text = ctypes.c_char_p(data_locked) 
      kernel32.GlobalUnlock(data_locked) 
    finally: 
     user32.CloseClipboard() 
    return text.value 


def sigtstp(): 
    """Raise EOFError from Ctrl-Z since SIGTSTP doesn't exist on Windows.""" 
    raise EOFError 


input_code = { 
    **ANSI, 
    'CSI': [['\xe0', '\x00'], ''], 
    'up': 'H', 
    'down': 'P', 
    'right': 'M', 
    'left': 'K', 
    'end': 'O', 
    'home': 'G', 
    'backspace': '\b', 
    'del': 'S', 
} 

에서 unix_specific.py :

"""Functions and variables for Debian-based Linux distros and macOS.""" 
import sys 
import os 
import tty 
import signal 
import termios 
from shared_stuff import ANSI 

def getwch(): 
    """Return a single character from user input without echoing. 

    ActiveState code, adapted from 
    <http://code.activestate.com/recipes/134892> by Danny Yoo under 
    the Python Software Foundation license. 

    """ 
    file_descriptor = sys.stdin.fileno() 
    old_settings = termios.tcgetattr(file_descriptor) 
    try: 
     tty.setraw(file_descriptor) 
     char = sys.stdin.read(1) 
    finally: 
     termios.tcsetattr(file_descriptor, termios.TCSADRAIN, old_settings) 
    return char 


def get_clipboard_data(): 
    """Return nothing; *NIX systems automagically change sys.stdin.""" 
    return '' 


def sigtstp(): 
    """Suspend the script.""" 
    os.kill(os.getpid(), signal.SIGTSTP) 


input_code = { 
    **ANSI, 
    'CSI': ['\x1b', '['], 
    'backspace': '\x7f', 
    'del': ['3', '~'], 
} 

readline_available.py 물 :

"""Provide functions for up and down arrows if readline is installed. 

Basically to prevent duplicate code and make it work on systems without 
readline. 

""" 
try: 
    import readline 
except ImportError: 
    import pyreadline as readline 
from shared_stuff import move_cursor 


def init_history_index(): 
    """Return index for last element of readline.get_history_item.""" 
    # readline.get_history_item is one-based 
    return readline.get_current_history_length() + 1 


def restore_history(history_index, replaced, cursor_position): 
    """Replace 'replaced' with history and return the replacement.""" 
    try: 
     replacement = readline.get_history_item(history_index) 
    except IndexError: 
     replacement = None 
    if replacement is not None: 
     move_cursor('right', len(replaced) - cursor_position) 
     print('\b \b' * len(replaced), end='', flush=True) 
     print(replacement, end='', flush=True) 
     return replacement 
    return replaced 


def store_and_replace_history(history_index, replacement, old_history): 
    """Store history and then replace it.""" 
    old_history[history_index] = readline.get_history_item(history_index) 
    try: 
     readline.replace_history_item(history_index - 1, replacement) 
    except AttributeError: 
    # pyreadline is incomplete 
     pass 


def handle_prev_history(history_index, replaced, old_history, 
         input_replaced, history_modified): 
    """Handle some up-arrow logic.""" 
    try: 
     history = readline.get_history_item(history_index - 1) 
    except IndexError: 
     history = None 
    if history is not None: 
     if history_index > readline.get_current_history_length(): 
      readline.add_history(replaced) 
      input_replaced = True 
     else: 
      store_and_replace_history(
       history_index, replaced, old_history) 
      history_modified = True 
     history_index -= 1 
    return (history_index, input_replaced, history_modified) 


def handle_next_history(history_index, replaced, old_history, 
         input_replaced, history_modified): 
    """Handle some down-arrow logic.""" 
    try: 
     history = readline.get_history_item(history_index + 1) 
    except IndexError: 
     history = None 
    if history is not None: 
     store_and_replace_history(history_index, replaced, old_history) 
     history_modified = True 
     history_index += 1 
     input_replaced = (not history_index 
          == readline.get_current_history_length()) 
    return (history_index, input_replaced, history_modified) 


def finalise_history(history_index, response, old_history, 
        input_replaced, history_modified): 
    """Change history before the response will be returned elsewhere.""" 
    try: 
     if input_replaced: 
      readline.remove_history_item(history_index - 1) 
     elif history_modified: 
      readline.remove_history_item(history_index - 1) 
      readline.add_history(old_history[history_index - 1]) 
    except AttributeError: 
    # pyreadline is also missing remove_history_item 
     pass 
    readline.add_history(response) 

readline_unavailable.py 물 :

에서 38,894,

:

"""Provide platform-independent functions and variables.""" 
ANSI = { 
    'CSI': '\x1b[', 
    'up': 'A', 
    'down': 'B', 
    'right': 'C', 
    'left': 'D', 
    'end': 'F', 
    'home': 'H', 
    'enter': '\r', 
    '^C': '\x03', 
    '^D': '\x04', 
    '^V': '\x16', 
    '^Z': '\x1a', 
} 


def move_cursor(direction, count=1): 
    """Move the text cursor 'count' times in the specified direction.""" 
    if direction not in ['up', 'down', 'right', 'left']: 
     raise ValueError("direction should be either 'up', 'down', 'right' " 
         "or 'left'") 
    # A 'count' of zero still moves the cursor, so this needs to be 
    # tested for. 
    if count != 0: 
     print(ANSI['CSI'] + str(count) + ANSI[direction], end='', flush=True) 


def line_insert(text, extra=''): 
    """Insert text between terminal line and reposition cursor.""" 
    if not extra: 
    # It's not guaranteed that the new line will completely overshadow 
    # the old one if there is no extra. Maybe something was 'deleted'? 
     move_cursor('right', len(text) + 1) 
     print('\b \b' * (len(text)+1), end='', flush=True) 
    print(extra + text, end='', flush=True) 
    move_cursor('left', len(text)) 

그리고 마지막으로, input_no_newline.py에 : 당신이 다른 운영 다룰 필요가 있기 때문에

#!/usr/bin/python3 
"""Provide an input function that doesn't echo a newline.""" 
try: 
from windows_specific import getwch, get_clipboard_data, sigtstp, input_code 
except ImportError: 
    from unix_specific import getwch, get_clipboard_data, sigtstp, input_code 
try: 
    from readline_available import (init_history_index, restore_history, 
            store_and_replace_history, 
            handle_prev_history, handle_next_history, 
            finalise_history) 
except ImportError: 
    from readline_unavailable import (init_history_index, restore_history, 
             store_and_replace_history, 
             handle_prev_history, handle_next_history, 
             finalise_history) 
from shared_stuff import ANSI, move_cursor, line_insert 


def input_no_newline(prompt=''): # pylint: disable=too-many-branches, too-many-statements 
    """Echo and return user input, except for the newline.""" 
    print(prompt, end='', flush=True) 
    response = '' 
    position = 0 
    history_index = init_history_index() 
    input_replaced = False 
    history_modified = False 
    replacements = {} 

    while True: 
     char = getwch() 
     if char in input_code['CSI'][0]: 
      char = getwch() 
      # Relevant input codes are made of two to four characters 
      if char == input_code['CSI'][1]: 
       # *NIX uses at least three characters, only the third is 
       # important 
       char = getwch() 
      if char == input_code['up']: 
       (history_index, input_replaced, history_modified) = (
        handle_prev_history(
         history_index, response, replacements, input_replaced, 
         history_modified)) 
       response = restore_history(history_index, response, position) 
       position = len(response) 
      elif char == input_code['down']: 
       (history_index, input_replaced, history_modified) = (
        handle_next_history(
         history_index, response, replacements, input_replaced, 
         history_modified)) 
       response = restore_history(history_index, response, position) 
       position = len(response) 
      elif char == input_code['right'] and position < len(response): 
       move_cursor('right') 
       position += 1 
      elif char == input_code['left'] and position > 0: 
       move_cursor('left') 
       position -= 1 
      elif char == input_code['end']: 
       move_cursor('right', len(response) - position) 
       position = len(response) 
      elif char == input_code['home']: 
       move_cursor('left', position) 
       position = 0 
      elif char == input_code['del'][0]: 
       if ''.join(input_code['del']) == '3~': 
        # *NIX uses '\x1b[3~' as its del key code, but only 
        # '\x1b[3' has currently been read from sys.stdin 
        getwch() 
       backlog = response[position+1 :] 
       response = response[:position] + backlog 
       line_insert(backlog) 
     elif char == input_code['backspace']: 
      if position > 0: 
       backlog = response[position:] 
       response = response[: position-1] + backlog 
       print('\b', end='', flush=True) 
       position -= 1 
       line_insert(backlog) 
     elif char == input_code['^C']: 
      raise KeyboardInterrupt 
     elif char == input_code['^D']: 
      raise EOFError 
     elif char == input_code['^V']: 
      paste = get_clipboard_data() 
      backlog = response[position:] 
      response = response[:position] + paste + backlog 
      position += len(paste) 
      line_insert(backlog, extra=paste) 
     elif char == input_code['^Z']: 
      sigtstp() 
     elif char == input_code['enter']: 
      finalise_history(history_index, response, replacements, 
          input_replaced, history_modified) 
      move_cursor('right', len(response) - position) 
      return response 
     else: 
      backlog = response[position:] 
      response = response[:position] + char + backlog 
      position += 1 
      line_insert(backlog, extra=char) 


def main(): 
    """Called if script isn't imported.""" 
    # "print(text, end='')" is equivalent to "print text,", and 'flush' 
    # forces the text to appear, even if the line isn't terminated with 
    # a '\n' 
    print('Hello, ', end='', flush=True) 
    name = input_no_newline() # pylint: disable=unused-variable 
    print(', how do you do?') 


if __name__ == '__main__': 
    main() 

당신이 볼 수 있듯이, 그것은하지 않는 많은 일이 그 정도의 시스템에서 동작하고 기본적으로 C가 아닌 파이썬에서 내장 함수를 다시 구현합니다. 나는 복잡한 응답 처리를 내장 함수에 남겨 두는 또 다른 대답으로 만든 간단한 TempHistory 클래스를 사용하는 것이 좋습니다.

2

새 라인을 만들지 않으려면 대신 getpass을 사용할 수 있습니다!

import sys, getpass 

def raw_input2(value="",end=""): 
    sys.stdout.write(value) 
    data = getpass.getpass("") 
    sys.stdout.write(data) 
    sys.stdout.write(end) 
    return data 
관련 문제