How to set a default editable string for raw_input?
Asked Answered
A

7

61

I'm using Python 2.7's raw_input to read from stdin.

I want to let the user change a given default string.

Code:

i = raw_input("Please enter name:")

Console:

Please enter name: Jack

The user should be presented with Jack but can change (backspace) it to something else.

The Please enter name: argument would be the prompt for raw_input and that part shouldn't be changeable by the user.

Anchylose answered 23/3, 2011 at 9:30 Comment(1)
Possible duplicate of Show default value for editing on Python input possible?Sherrell
B
83

You could do:

i = raw_input("Please enter name[Jack]:") or "Jack"

This way, if user just presses return without entering anything, "i" will be assigned "Jack".

Bibliopegy answered 3/12, 2013 at 12:34 Comment(3)
This doesn't fit the question. Jack is not editable.Chemotaxis
But this is a common Unix pattern for providing default input. If you want to accept the default just hit enter.Villar
@Villar The question wasn't about common Unix pattern.Chemotaxis
P
32

Python2.7 get raw_input and set a default value:

Put this in a file called a.py:

import readline
def rlinput(prompt, prefill=''):
   readline.set_startup_hook(lambda: readline.insert_text(prefill))
   try:
      return raw_input(prompt)
   finally:
      readline.set_startup_hook()

default_value = "an insecticide"
stuff = rlinput("Caffeine is: ", default_value)
print("final answer: " + stuff)

Run the program, it stops and presents the user with this:

el@defiant ~ $ python2.7 a.py
Caffeine is: an insecticide

The cursor is at the end, user presses backspace until 'an insecticide' is gone, types something else, then presses enter:

el@defiant ~ $ python2.7 a.py
Caffeine is: water soluable

Program finishes like this, final answer gets what the user typed:

el@defiant ~ $ python2.7 a.py 
Caffeine is: water soluable
final answer: water soluable

Equivalent to above, but works in Python3:

import readline    
def rlinput(prompt, prefill=''):
   readline.set_startup_hook(lambda: readline.insert_text(prefill))
   try:
      return input(prompt)
   finally:
      readline.set_startup_hook()

default_value = "an insecticide"
stuff = rlinput("Caffeine is: ", default_value)
print("final answer: " + stuff)

More info on what's going on here:

https://mcmap.net/q/237908/-show-default-value-for-editing-on-python-input-possible

Positronium answered 13/4, 2016 at 18:51 Comment(3)
Is this supposed to work in Windows too or does it only work in Linux?Wendell
you are genius! TY so much!Awe
@ChaimG: Unfotunately: pip install readline yields error: this module is not meant to work on WindowsHellcat
K
7

In dheerosaur's answer If user press Enter to select default value in reality it wont be saved as python considers it as '' string so Extending a bit on what dheerosaur.

default = "Jack"
user_input = raw_input("Please enter name: %s"%default + chr(8)*4)
if not user_input:
    user_input = default

Fyi .. The ASCII value of backspace is 08

Keratose answered 23/3, 2011 at 12:12 Comment(3)
That's a neat trick, thanks. Still not what I want because the user can't really change the given default string or use the arrow keys for navigation. Of course one could work around that but that's a bit out of scope for such a little feature.Anchylose
Shouldn't it be 'chr(8)*len(default)' ?Nakashima
Jack is just printed but not set as default.Chemotaxis
V
6

I only add this because you should write a simple function for reuse. Here is the one I wrote:

def default_input( message, defaultVal ):
    if defaultVal:
        return raw_input( "%s [%s]:" % (message,defaultVal) ) or defaultVal
    else:
        return raw_input( "%s " % (message) )
Villar answered 8/9, 2014 at 22:20 Comment(4)
This doesn't fit the question.Chemotaxis
I re-read the question and I still think it does. You might want to explain your position better.Villar
@chubbsndubs Cited from the question: "but can change (backspace) it to something else". This means that the user should be able to edit the default value.Chemotaxis
You're being overly pedantic. My suggestion gives the OP the feature they requested in a slightly different way. It's implied that if the OP can alter their requirements, which I see as very minor change, then this solution will work for them. If not fine the answer is you can't do it with raw_input(), and you're looking at a non-portable solution using readline maybe.Villar
Y
5

On platforms with readline, you can use the method described here: https://mcmap.net/q/237908/-show-default-value-for-editing-on-python-input-possible

On Windows, you can use the msvcrt module:

from msvcrt import getch, putch

def putstr(str):
    for c in str:
        putch(c)

def input(prompt, default=None):
    putstr(prompt)
    if default is None:
        data = []
    else:
        data = list(default)
        putstr(data)
    while True:
        c = getch()
        if c in '\r\n':
            break
        elif c == '\003': # Ctrl-C
            putstr('\r\n')
            raise KeyboardInterrupt
        elif c == '\b': # Backspace
            if data:
                putstr('\b \b') # Backspace and wipe the character cell
                data.pop()
        elif c in '\0\xe0': # Special keys
            getch()
        else:
            putch(c)
            data.append(c)
    putstr('\r\n')
    return ''.join(data)

Note that arrows keys don't work for the windows version, when it's used, nothing will happen.

Yokum answered 23/7, 2012 at 16:20 Comment(0)
D
2

For windows users with gitbash/msys2 or cygwin you can use it's built in readline through python subprocess. It is a sort of hack but works quite well and doesn't require any third party code. For personal tools this works really well.

Msys2 specific: If you want ctrl+c to immediately exit, you will need to run your program with
winpty python program.py

import subprocess
import shlex

def inputMsysOrCygwin(prompt = "", prefilled = ""):
    """Run your program with winpty python program.py if you want ctrl+c to behave properly while in subprocess"""
    try:
        bashCmd = "read -e -p {} -i {} bash_input; printf '%s' \"$bash_input\"".format(shlex.quote(prompt), shlex.quote(prefilled))
        userInput = subprocess.check_output(["sh", "-c", bashCmd], encoding='utf-8')
        return userInput
    except FileNotFoundError:
        raise FileNotFoundError("Invalid environment: inputMsysOrCygwin can only be run from bash where 'read' is available.")

userInput = ""
try:
    #cygwin or msys2 shell
    userInput = inputMsysOrCygwin("Prompt: ", "This is default text")
except FileNotFoundError:
    #cmd or powershell context where bash and read are not available 
    userInput = input("Prompt [This is default text]: ") or "This is default text"

print("userInput={}".format(userInput))
Disposition answered 20/12, 2019 at 17:7 Comment(0)
S
-4

Try this: raw_input("Please enter name: Jack" + chr(8)*4)

The ASCII value of backspace is 08.

Sammer answered 23/3, 2011 at 11:19 Comment(2)
Jack is just printed but not set as default.Chemotaxis
@Chemotaxis Thanks for pointing out. Please feel free to edit the answer.Sammer

© 2022 - 2024 — McMap. All rights reserved.