How to put text in input line: how to ask for user input on the command line while providing a 'default' answer that the user can edit or delete?

后端 未结 4 1529
忘了有多久
忘了有多久 2020-12-18 21:07

I am creating a Python script that asks for input from the command line. The user will have the ability to edit a part of a file. I can ask for the new information and overw

相关标签:
4条回答
  • 2020-12-18 21:23

    You should just have 2 variables: one for standard string, one for string that will user change by itself. Like:

    str1 = 'String that is standard'
    str2 = str1 #it usually will be standard string
    usr = input('your text goes here')
    if len(usr) != 0:
        str2 = usr
    #and here goes code for writing string into file
    
    0 讨论(0)
  • 2020-12-18 21:33

    I have written a line editor which hopefully does what you are looking for. But it is a quick-and-dirty hack. It is Windows only and written with CPython 3.6.5 on Windows 10, so its use might be limited. It has been tested on codepage 1252 (ANSI Latin 1; Western European (Windows)) and codepage 65001 (utf-8). It is very basic and a bit sluggish as it is not speed-optimized. (I should rewrite it in C but I do not have the time.) It is hardly tested and poorly documented.

    import msvcrt
    import os
    import sys
    
    if os.name != 'nt':
        raise NotImplementedError('This module works only on MS Windows!')
    
    CTRL_00         = 0
    CTRL_E0         = 224
    KEY_BACKSPACE   = 8
    KEY_DELETE      = 83                                            # CTRL
    KEY_END         = 79                                            # CTRL
    KEY_ESC         = 27
    KEY_HOME        = 71                                            # CTRL
    KEY_INSERT      = 82                                            # CTRL
    KEY_LEFT        = 75                                            # CTRL
    KEY_RETURN      = 13
    KEY_RIGHT       = 77                                            # CTRL
    
    flush = sys.stdout.flush
    write = sys.stdout.write
    
    mode    = ('[OVR]> ', '[INS]> ')                                # overwrite, insert
    prefix  = len(mode[0])
    
    def _update_line(insert, source, length, line, target):
        """Write a new line and position the cursor.
        source: previous cursor position
        length: old line length
        line:   edited line
        target: next cursor position
        """
        write('\b' * source)                                        # set cursor to start of line
        write(' ' * length)                                         # erase old line
        write('\b' * length)                                        # again, set cursor to start of line
        write(mode[insert] + line[prefix:])                         # write updated line
        write('\b' * (len(line) - target))                          # set cursor to new position
        flush()                                                     # write buffer to screen
    
    def mswin_line_edit(default_string, insert=True):
        """Edit a MS Windows CLI line."""
    
        insert = insert
        line = mode[insert] + default_string
        count = len(line)
        before = line[:count]
        after = line[count:]
        print(line, end='', flush=True)
        cursor = count
    
        while True:
            key = msvcrt.getwch()
            num = ord(key)
            if num == KEY_ESC:                                      # abort edit
                return default_string
            if num == KEY_RETURN:                                   # finish edit
                return line
            if num == KEY_BACKSPACE:                                # delete character before cursor
                if cursor > prefix:
                    before = line[:cursor - 1]
                    after = line[cursor:]
                    line = before + after
                    _update_line(insert, cursor, count, line, cursor - 1)
                    cursor -= 1
                    count = len(line)
            elif num == CTRL_E0 or num == CTRL_00:                  # CTRL
                ctrl = ord(msvcrt.getwch())
                if ctrl == KEY_END:                                     # set cursor after last character
                    if cursor < count:
                        before = line
                        after = ''
                        _update_line(insert, cursor, count, line, count)
                        cursor = count
                elif ctrl == KEY_HOME:                                  # set cursor before first character
                    if cursor > prefix:
                        before = ''
                        after = line
                        _update_line(insert, cursor, count, line, prefix)
                        cursor = prefix
                elif ctrl == KEY_LEFT:                                  # move cursor 1 character to the left
                    if cursor > prefix:
                        before = line[:cursor]
                        after = line[cursor:]
                        _update_line(insert, cursor, count, line, cursor - 1)
                        cursor -= 1
                elif ctrl == KEY_RIGHT:                                 # move cursor 1 character to the right
                    if cursor < count:
                        before = line[:cursor]
                        after = line[cursor:]
                        _update_line(insert, cursor, count, line, cursor + 1)
                        cursor += 1
                elif ctrl == KEY_DELETE:                                # delete character after cursor
                    if cursor < count:
                        before = line[:cursor]
                        after = line[cursor + 1:]
                        line = before + after
                        _update_line(insert, cursor, count, line, cursor)
                        count = len(line)
                elif ctrl == KEY_INSERT:                                # switch insert/overwrite mode
                    insert ^= True
                    _update_line(insert, cursor, count, line, cursor)
            else:                                                   # ordinary character
                before = line[:cursor] + key
                if insert:
                    after = line[cursor:]
                else:
                    after = line[cursor + 1:]
                line = before + after
                _update_line(insert, cursor, count, line, cursor + 1)
                cursor += 1
                count = len(line)
    
    if __name__ == '__main__':
        test_string = input('test string: ')
        result = mswin_line_edit(test_string)
        print(f'\n{result}')
    
    0 讨论(0)
  • 2020-12-18 21:35

    You could do it with tkinter:

    from tkinter import *
    def enter():
        global commandEntry
        command = commandEntry.get()
        # Do stuff with command
        commandEntry.delete(0, END)
    def edit_line(line):
        global commandEntry
        commandEntry.insert(0, line)
    root = Tk()
    messageVar = StringVar()
    messageVar.set("Enter a command:")
    message = Label(root, textvariable=messageVar)
    commandEntry = Entry(root)
    enterButton = Button(root, text="Enter", command=enter)
    root.mainloop()
    
    0 讨论(0)
  • 2020-12-18 21:36

    Unfortunately, I don't know if kind of input() with default value is available in standard library.

    There is an external solution - use win32console as mentioned in this answer. However, it has two pitfalls as far as I can see. First, the import is bundled in a package pywin32. So you would use pip install pywin32, except it does not work, because of the second pitfall: the information about the package at pypi is outdated, it says that package is incompatible with Python 3.4...

    But in fact, it can work! You should follow the "Download URL" visible at pypi project page (i.e. https://sourceforge.net/projects/pywin32/files/pywin32/ ) and install latest build. I just installed build 219 for Py3.4, as I myself also use this Python version. On the page installers are provided for several Python versions for 32bit and 64bit Windows.

    Also, I've tweaked the code from above-linked SO answer to work in Python 3:

    import win32console
    
    _stdin = win32console.GetStdHandle(win32console.STD_INPUT_HANDLE)
    
    def input_def(prompt, default=''):
        keys = []
        for c in str(default):
            evt = win32console.PyINPUT_RECORDType(win32console.KEY_EVENT)
            evt.Char = c
            evt.RepeatCount = 1
            evt.KeyDown = True
            keys.append(evt)
    
        _stdin.WriteConsoleInput(keys)
        return input(prompt)
    
    if __name__ == '__main__':
        name = input_def('Folder name: ', 'it works!!!')
        print()
        print(name)
    

    This works on my Windows machine... If this does not work on yours, can you provide the error message?

    0 讨论(0)
提交回复
热议问题