I have a input.txt file with the following content.
3
4 5
I want to use this as a standard input by using the following command in the command line.
python a.py < input.txt
In the a.py script, I am trying to read the input line by line using input() function. I know there are better ways to read the stdin, but I need to use input() function.
A naive approach of
line1 = input()
line2 = input()
did not work. I get the following error message.
File "<string>", line 1
4 5
^
SyntaxError: unexpected EOF while parsing
That way is ok, it works:
read = input()
print(read)
but you are just reading one line.
From the input() doc:
The function then reads a line from input, converts it to a string
(stripping a trailing newline), and returns that.
That means that if the file does not end with a blank line, or what is the same, the last nonblank line of the file do not end with an end of line character, you will get exceptions.SyntaxError and the last line will not be read.
You mention HackerRank; looking at some of my old submissions, I think I opted to give up on input in lieu of sys.stdin manipulations. input() is very similar to next(sys.stdin), but the latter will handle EOF just fine.
By way of example, my answer for https://www.hackerrank.com/challenges/maximize-it/
import sys
import itertools
# next(sys.stdin) is functionally identical to input() here
nK, M = (int(n) for n in next(sys.stdin).split())
# but I can also iterate over it
K = [[int(n) for n in line.split()][1:] for line in sys.stdin]
print(max(sum(x**2 for x in combo) % M for combo in itertools.product(*K)))
Related
I am studying python file I/O. I made a simple program(main.py).
My goal is read line by line and write line by line.
fstream = open("input2.txt", 'r');
line = fstream.readline()
while line:
print(line);
line = fstream.readline()
fstream.close()
below are my input2.txt file
start.
hello world.
hello python.
I am studying file I/O in python
end.
when I run python program
python main.py
Then, result is ...
start.
hello world.
hello python.
I am studying file I/O in python
end.
That is not the same as I expected.
So I modified the main.py
fstream = open("input2.txt", 'r');
line = fstream.read().split("\n")
while line:
print(line);
line = fstream.read().split("\n")
fstream.close()
However my program diged into infinite loop.
picture of infinite loop
To solve this problem what should I do?
The result I expected is the following.
start.
hello world.
hello python.
I am studying file I/O in python
end.
The print function will automatically add a new line character. So
print msg
will print content of variable msg followed by a new line
If you do not want python to print the trailing new line, you have to add a comma to the end. This will print msg without the trailing newline. And if msg already has a new line which is the case when reading new lines from a file, you will see a single new line in place of double new lines.
print msg,
If you are using python 3 where print is called as a function, you can specify the end argument. See https://docs.python.org/3/library/functions.html#print
print(msg, end = '')
First of all, use a with statement to open the file so that you don't need to close it explicitly. Second, don't use a while loop for this; you can iterate over a file directly. Third, use the rstrip method to remove any trailing whitespace from line you read (or rstrip('\n') to remove only trailing newlines):
with open("input2.txt", 'r') as fstream:
for line in fstream:
line = line.rstrip('\n')
print(line)
In addition to the answers above; You can also use .splitlines()
fstream = open("input2.txt", 'r');
line = fstream.readline().splitlines()
while line:
print(line[0]);
line = fstream.readline().splitlines()
fstream.close()
Everyone knows how to count the characters from STDIN in C. However, when I tried to do that in python3, I find it is a puzzle. (counter.py)
import sys
chrCounter = 0
for line in sys.stdin.readline():
chrCounter += len(line)
print(chrCounter)
Then I try to test the program by
python3 counter.py < counter.py
The answer is only the length of the first line "import sys". In fact, the program ONLY read the first line from the standard input, and discard the rest of them.
It will be work if I take the place of sys.stdin.readline by sys.stdin.read()
import sys
print(len(sys.stdin.read()))
However, it is obviously, that the program is NOT suitable for a large input. Please give me a elegant solution. Thank you!
It's simpler:
for line in sys.stdin:
chrCounter += len(line)
The file-like object sys.stdin is automatically iterated over line by line; if you call .readline() on it, you only read the first line (and iterate over that character-by-character); if you call read(), then you'll read the entire input into a single string and iterate over that character-by.character.
The answer from Tim Pietzcker is IMHO the correct one. There are 2 similar ways of doing this. Using:
for line in sys.stdin:
and
for line in sys.stdin.readlines():
The second option is closer to your original code. The difference between these two options is made clear by using e.g. the following modification of the for-loop body and using keyboard for input:
for line in sys.stdin.readlines():
line_len = len(line)
print('Last line was', line_len, 'chars long.')
chrCounter += len(line)
If you use the first option (for line in sys.stdin:), then the lines are processed right after you hit enter.
If you use the second option (for line in sys.stdin.readlines():), then the whole file is first read, split into lines and only then they are processed.
If I just wanted a character count, I'd read in blocks at a time instead of lines at a time:
# 4096 chosen arbitrarily. Pick any other number you want to use.
print(sum(iter(lambda:len(sys.stdin.read(4096)), 0)))
I would like to read the next logical line from a file into python, where logical means "according to the syntax of python".
I have written a small command which reads a set of statements from a file, and then prints out what you would get if you typed the statements into a python shell, complete with prompts and return values. Simple enough -- read each line, then eval. Which works just fine, until you hit a multi-line string.
I'm trying to avoid doing my own lexical analysis.
As a simple example, say I have a file containing
2 + 2
I want to print
>>> 2 + 2
4
and if I have a file with
"""Hello
World"""
I want to print
>>>> """Hello
...World"""
'Hello\nWorld'
The first of these is trivial -- read a line, eval, print. But then I need special support for comment lines. And now triple quotes. And so on.
You may want to take a look at the InteractiveInterpreter class from the code module .
The runsource() method shows how to deal with incomplete input.
Okay, so resi had the correct idea. Here is my trivial code which does the job.
#!/usr/bin/python
import sys
import code
class Shell(code.InteractiveConsole):
def write(data):
print(data)
cons = Shell()
file_contents = sys.stdin
prompt = ">>> "
for line in file_contents:
print prompt + line,
if cons.push(line.strip()):
prompt = "... "
else:
prompt = ">>> "
I'm writing a script to convert very simple function documentation to XML in python. The format I'm using would convert:
date_time_of(date) Returns the time part of the indicated date-time value, setting the date part to 0.
to:
<item name="date_time_of">
<arg>(date)</arg>
<help> Returns the time part of the indicated date-time value, setting the date part to 0.</help>
</item>
So far it works great (the XML I posted above was generated from the program) but the problem is that it should be working with several lines of documentation pasted, but it only works for the first line pasted into the application. I checked the pasted documentation in Notepad++ and the lines did indeed have CRLF at the end, so what is my problem?
Here is my code:
mainText = input("Enter your text to convert:\r\n")
try:
for line in mainText.split('\r\n'):
name = line.split("(")[0]
arg = line.split("(")[1]
arg = arg.split(")")[0]
hlp = line.split(")",1)[1]
print('<item name="%s">\r\n<arg>(%s)</arg>\r\n<help>%s</help>\r\n</item>\r\n' % (name,arg,hlp))
except:
print("Error!")
Any idea of what the issue is here?
Thanks.
input() only reads one line.
Try this. Enter a blank line to stop collecting lines.
lines = []
while True:
line = input('line: ')
if line:
lines.append(line)
else:
break
print(lines)
The best way to handle reading lines from standard input (the console) is to iterate over the sys.stdin object. Rewritten to do this, your code would look something like this:
from sys import stdin
try:
for line in stdin:
name = line.split("(")[0]
arg = line.split("(")[1]
arg = arg.split(")")[0]
hlp = line.split(")",1)[1]
print('<item name="%s">\r\n<arg>(%s)</arg>\r\n<help>%s</help>\r\n</item>\r\n' % (name,arg,hlp))
except:
print("Error!")
That said, It's worth noting that your parsing code could be significantly simplified with a little help from regular expressions. Here's an example:
import re, sys
for line in sys.stdin:
result = re.match(r"(.*?)\((.*?)\)(.*)", line)
if result:
name = result.group(1)
arg = result.group(2).split(",")
hlp = result.group(3)
print('<item name="%s">\r\n<arg>(%s)</arg>\r\n<help>%s</help>\r\n</item>\r\n' % (name,arg,hlp))
else:
print "There was an error parsing this line: '%s'" % line
I hope this helps you simplify your code.
Patrick Moriarty,
It seems to me that you didn't particularly mention the console and that your main concern is to pass several lines together at one time to be treated. There's only one manner in which I could reproduce your problem: it is, executing the program in IDLE, to copy manually several lines from a file and pasting them to raw_input()
Trying to understand your problem led me to the following facts:
when data is copied from a file and pasted to raw_input() , the newlines \r\n are transformed into \n , so the string returned by raw_input() has no more \r\n . Hence no split('\r\n') is possible on this string
pasting in a Notepad++ window a data containing isolated \r and \n characters, and activating display of the special characters, it appears CR LF symbols at all the extremities of the lines, even at the places where there are \r and \n alone. Hence, using Notepad++ to verify the nature of the newlines leads to erroneous conclusion
.
The first fact is the cause of your problem. I ignore the prior reason of this transformation affecting data copied from a file and passed to raw_input() , that's why I posted a question on stackoverflow:
Strange vanishing of CR in strings coming from a copy of a file's content passed to raw_input()
The second fact is responsible of your confusion and despair. Not a chance....
.
So, what to do to solve your problem ?
Here's a code that reproduce this problem. Note the modified algorithm in it, replacing your repeated splits applied to each line.
ch = "date_time_of(date) Returns the time part.\r\n"+\
"divmod(a, b) Returns quotient and remainder.\r\n"+\
"enumerate(sequence[, start=0]) Returns an enumerate object.\r\n"+\
"A\rB\nC"
with open('funcdoc.txt','wb') as f:
f.write(ch)
print "Having just recorded the following string in a file named 'funcdoc.txt' :\n"+repr(ch)
print "open 'funcdoc.txt' to manually copy its content, and paste it on the following line"
mainText = raw_input("Enter your text to convert:\n")
print "OK, copy-paste of file 'funcdoc.txt' ' s content has been performed"
print "\nrepr(mainText)==",repr(mainText)
try:
for line in mainText.split('\r\n'):
name,_,arghelp = line.partition("(")
arg,_,hlp = arghelp.partition(") ")
print('<item name="%s">\n<arg>(%s)</arg>\n<help>%s</help>\n</item>\n' % (name,arg,hlp))
except:
print("Error!")
.
Here's the solution mentioned by delnan : « read from the source instead of having a human copy and paste it. »
It works with your split('\r\n') :
ch = "date_time_of(date) Returns the time part.\r\n"+\
"divmod(a, b) Returns quotient and remainder.\r\n"+\
"enumerate(sequence[, start=0]) Returns an enumerate object.\r\n"+\
"A\rB\nC"
with open('funcdoc.txt','wb') as f:
f.write(ch)
print "Having just recorded the following string in a file named 'funcdoc.txt' :\n"+repr(ch)
#####################################
with open('funcdoc.txt','rb') as f:
mainText = f.read()
print "\nfile 'funcdoc.txt' has just been opened and its content copied and put to mainText"
print "\nrepr(mainText)==",repr(mainText)
print
try:
for line in mainText.split('\r\n'):
name,_,arghelp = line.partition("(")
arg,_,hlp = arghelp.partition(") ")
print('<item name="%s">\n<arg>(%s)</arg>\n<help>%s</help>\n</item>\n' % (name,arg,hlp))
except:
print("Error!")
.
And finally, here's the solution of Python to process the altered human copy: providing the splitlines() function that treat all kind of newlines (\r or \n or \r\n) as splitters. So replace
for line in mainText.split('\r\n'):
by
for line in mainText.splitlines():
I'm trying to read in the following text from the command-line in Python 3 (copied verbatim, newlines and all):
lcbeika
rraobmlo
grmfina
ontccep
emrlin
tseiboo
edosrgd
mkoeys
eissaml
knaiefr
Using input, I can only read in the first word as once it reads the first newline it stops reading.
Is there a way I could read in them all without iteratively calling input?
You can import sys and use the methods on sys.stdin for example:
text = sys.stdin.read()
or:
lines = sys.stdin.readlines()
or:
for line in sys.stdin:
# Do something with line.
if you are passing the text into your script as a file , you can use readlines()
eg
data=open("file").readlines()
or you can use fileinput
import fileinput
for line in fileinput.input():
print line