# ---
# jupyter:
#   jupytext:
#     text_representation:
#       extension: .py
#       format_name: light
#       format_version: '1.5'
#       jupytext_version: 1.14.4
#   kernelspec:
#     display_name: Python 3
#     language: python
#     name: python3
# ---

# # Module 5: Data Structures - Files

# +
'''
The files are the secondary memory that is not erased even when the power is turned off.
Files could be text files, like the ones in the examples below. Or, they could be binary
files, such as databases. We will work with a text file called 'mbox.txt'

Get the file 'mbox.txt'
Download the file mbox.txt from https://www.py4e.com/code3/mbox.txt. Go to this website, open the file, select contents
with ctrl-a, and copy with ctrl-c. 

>> Now go to Jupyter home >> File >> New (see upper right corner) >> in the dropdown menu 
select 'Text  File' >> this will open new text file >> paste copied contents of mbox.txt here with ctrl-v >> File >> 
>> Save (it will save as 'untitled1.txt' >> rename it as 'mbox.txt'
The files are the secondary memory that is not erased even when the power is turned off.
Files could be text files, like the ones in the examples below. Or, they could be binary
files, such as databases. We will work with a text file called 'mbox.txt'

Get the file 'mbox.txt'
Download the file mbox.txt from https://www.py4e.com/code3/mbox.txt. Go to this website, open the file, select contents
with ctrl-a, and copy with ctrl-c. 

>> Now go to Jupyter home >> File >> New (see upper right corner) >> in the dropdown menu 
select 'Text  File' >> this will open new text file >> paste copied contents of mbox.txt here with ctrl-v >> File >> 
>> Save (it will save as 'untitled1.txt' >> rename it as 'mbox.txt' 
'''

# opening the file mbox.txt. If open is successful, operating system will return a file handle
# file handle is not actual data contained in the file but it is a handle that can be used to read the file

fhand = open('mbox.txt')    # assigning a name to the file handle
print(fhand)

# -

# Trying to open a file that does not exist wil return an error
print('Now open a nonexistent file')
fhand = open(stuff.txt)

# # Text files and lines

# +
"""
To break a file up in lines, the backslash-n character i.e. "\n" is used. 
"""
# The newline character (\n)

stuff = 'Hello\n World!'
print('break Hello World across lines:\n', stuff)
# -

# break X \n Y across lines. Note that backslash-n is also embedded in print() function
stuff = 'X\n Y'
print('break string acrosss lines:\n' , stuff)

# finding length of string
linelength= len(stuff)
print("length of the string 'stuff':", linelength)  

# # Reading files
#
# ## Download file mbox-short.txt from www.py4e.com/code3/mbox-short.txt
# ### Be careful. If the file is not copied to your python directory, it will not open

# +
# Counting lines in a file using a for-loop
#     The advantage of using the for-loop is that the size of the file does not matter, as the loop goes 
#        through it one line at a time

#      Also when a for-loop is used, python inserts a newline character after each line

fhand = open('mbox-short.txt')
count = 0
for line in fhand:
    count = count + 1
print('Line Count:', count)

# +
'''
For small files, the read() method on the file handle can be used to read the whole file into a string
'''

fhand = open('mbox-short.txt')
inp = fhand.read()
print(len(inp))              # printing the length of the string

# Reading first 20 characters in the string 
print(inp[:20])
# -

# #     Searching through a file
# ##          Example: finding a 'From:' line in a file consisting of email messages
# ###           Use startswith() string method on each line 

string='hello Taha how are you'
string.find('Taha')

# +
fhand = open('mbox-short.txt')

for line in fhand:
    if line.startswith('From:'):   
        print(line)
# -

# This is too long a list.
# What if we want just the email addresses of first five senders?¶
#

# +
# We will initialize a count variable at zero, and then increment it by 1 in each iteration
# When the count reaches 5, we use if-statement, followed by 'continue' command to skip the printing 
#        and to return to top of the loop without executing the remaing comamnds 

fhand = open('mbox-short.txt')
count = 0
for line in fhand:
    if line.startswith('From:'):
        count = count + 1
        if count > 5:
            continue
            
        print(line)
print(" ||||||| Do another example using the 'break' command to jump out of the loop |||||||")
# -

# Break command
# What is the difference in the actions of 'continue' and 'break' commands?

# +
# We will initialize a count variable at zero, and then increment it by 1 in each iteration
# When the count reaches 5, we use if-statement, followed by 'continue' command to skip the printing
# At this point we could also have used a 'break' command to jump out of the loop

fhand = open('mbox-short.txt')
count = 0
for line in fhand:
    if line.startswith('From:'):
        count = count + 1
        if count > 5:
            break                  #break comamnd to jump out of the loop
            
        print(line)
print(" ||||||| Break command takes us out of the loop |||||||")
# -

# Use rstrip() string method to get rid of line double spacing
# There is a newline character at the end of each line. The rstrip method strips white space from the right-side of the string

# +
fhand = open('mbox-short.txt')

for line in fhand:
    line = line.rstrip()
    if line.startswith('From:'):   
        print(line)
# -

# Using the string method find()
# Finding emails with university of Cape Town address ( @uct.ac.za )¶
#

# +
'''
The string method find() returns the position of substring within a string that we are 
looking for alternatively it returns -1 if the substring is not found
'''
# Our strategy is to skip printing if '@uct.ac.za' substring not found, i.e. find() returns -1

fhand = open('mbox-short.txt')

for line in fhand:
    line = line.rstrip()
    if line.find('@uct.ac.za') == -1:
        continue                            #skip remaining lines in body of loop when if-condition false
    print(line)
# -

# But you just want all the senders emails, not the Author: and X-Authentication lines
#
# Try this now
#
# Solution is provided

# +
# Our strategy is to skip printing if '@uct.ac.za' substring not found, i.e. find() returns -1

fhand = open('mbox-short.txt')

for line in fhand:
    line = line.rstrip()
    if line.find('@uct.ac.za') == -1 or line.startswith('A') or line.startswith('X'):
        continue                            #skip remaining lines in body of loop when if-condition false
    print(line)

# -

# ##Letting User Choose the File Name
#
# This is useful when we want to use the same program on different files
#
# The user is asked to provide the file name
#
#

# +
fname = input('Enter filename: ')
fhand = open(fname)

count = 0
for line in fhand:
    if line.startswith('Subject:'):
        count = count + 1
print('There are', count, 'Subject lines in', fname)
# -

# Using try, except, and open
# open() may fail sometimes
#
# try is an insurance policy against open() failing if the user typed somehting crazy
#
# except specifies the action to be taken when an exception occurs (such as invalid user input)
#
# Under these circumstance we may have to use exit() to exit the program

# +
# We use try/except to protect the opening of the file. the rest of the program is as above
# When prompted for file name type 'mbox-short.txt'
# Run this program again. When prompted for file name second time, type 'ala bla'

fname = input('Enter the file name: ')
try:
    fhand = open(fname)
except:
    print('File cannot be opened:', fname)
    exit()
    
count = 0
for line in fhand:
    if line.startswith('From:'):
        count = count + 1
print('There were', count, 'Subject lines in the file', fname)

    

# print("Now try the same program again with file name 'alaa blaa' ")
# -



# # Writing files
#
# Open file with mode "w" as the second parameter
#

# +
"""
To write file you have to first open it with "w", and create a file handle
Then add lines to it using write() method of the file handle object

Suppose we want to create anew file 'output.txt' and then add lines to it one by one
"""

# creating file handle object with open() command anad 'w' as second parameter
fout = open('output.txt', 'w')
print('Print file handle:\n ', fout)
print()

# Now add lines to file 'output.txt' for which a file handle object 'fout' has been created above
# use write() method for the file handle object to add lines
# note the write() method will also returns the number of characters written

line1 = "This here's the wattle, \n"
fout.write(line1)

line2 = 'the emblem of our land. \n'
fout.write(line2)

# close the file
fout.close()

# Now lets count how many lines there are in output.txt
# We have to open it and create a file handle object first, then write a for-loop to count lines

fhand = open('output.txt')
count = 0
for line in fhand:
    count = count + 1
    print(line)
print('The number of lines in the file output.txt is: ', count)



fout = open('output.txt', 'w')
print('Print file handle:\n ', fout)
print()

# +
# Now add lines to file 'output.txt' for which a file handle object 'fout' has been created above
# use write() method for the file handle object to add lines
# note the write() method will also returns the number of characters written

line1 = "This here's the wattle, \n"
fout.write(line1)

line2 = 'the emblem of our land. \n'
fout.write(line2)

# close the file
fout.close()

# +
# Now lets count how many lines there are in output.txt
# We have to open it and create a file handle object first, then write a for-loop to count lines

fhand = open('output.txt')
count = 0
for line in fhand:
    count = count + 1
    print(line)
print('The number of lines in the file output.txt is: ', count)
# -



StarcoderdataJupyterScriptsDedupFiltered