头歌python通关:文件操作和异常处理

第1关:实现json解析器中数字和字符串的解析

本关任务:编写一个json解析器,实现对数字和字符串的解析

平台会对你编写的代码进行测试:

测试输入: {"name":"小明","age":14,"gender":true,"grade":null,"skills":["JavaScript","Java"]} 预期输出: {'name': 15, 'age': 14, 'gender': True, 'grade': None, 'skills': ['JavaScript', 'Java']}

测试输入:{"name":} 预期输出:Exception: Unexpected Token at position 3

from typing import List
from enum import Enum

"""
全局标量定义来表示符合 JSON 所规定的数据类型
(学生可以使用字典结构表示此结构)
其中:
BEGIN_OBJECT({)
END_OBJECT(})
BEGIN_ARRAY([)
END_ARRAY(])
NULL(null)
NUMBER(数字)
STRING(字符串)
BOOLEAN(true/false)
SEP_COLON(:)
SEP_COMMA(,)
"""

# Signal token
BEGIN_OBJECT = 1
BEGIN_ARRAY = 2
END_OBJECT = 4
END_ARRAY = 8

# variable token
NULL_TOKEN = 16
NUMBER_TOKEN = 32
STRING_TOKEN = 64
BOOL_TOKEN = 128

# separator token
COLON_TOKEN = 256
COMMA_TOKEN = 512

# end signal
END_JSON = 65536

# json index
json_index = 0

def token_parse(json_str: str, json_index: int) -> (tuple, int):
    """
    完成词法解析,返回token
    :param json_str: 输入的json字符串
    :param json_index: json字符串的位置
    :return: 返回已处理好的token和json字符串的位置
    """
    def read_num(json_index:int):
        """
        处理数字
        :param json_index: json字符串的位置
        :return: 返回处理数字后的token序列
        """
        ##你的代码在这里##
        i=1
        for ch in json_str[json_index+1:]:
            if ch!=',':
                i=i+1
            else:
                break
        rem=json_str[json_index:json_index+i]
        return (NUMBER_TOKEN,rem),json_index+i
    def read_str(json_index: int):
        """
        处理字符串
        :param json_index: json字符串的位置
        :return: 返回处理字符串后的token序列
       """
         ##你的代码在这里##
        j=2
        for ch in json_str[json_index+1:]:
            if ch!='"':
                j=j+1
            else:
                break
        rem=json_str[json_index+1:json_index+j-1]
        return (STRING_TOKEN,rem),json_index+j
    def read_null():
        """
        处理null
        :return: 返回处理null后的token序列
        """
        rem = json_str[json_index: json_index + 4]
        return (NULL_TOKEN, rem), json_index + 4

    def read_bool(s: str):
        """
        处理true,false
        :param s: json字符串
        :return: 返回处理true,false后的token序列
        """
        if s == 't':
            rem = json_str[json_index: json_index + 4]
            return (BOOL_TOKEN, rem), json_index + 4
        else:
            rem = json_str[json_index: json_index + 5]
            return (BOOL_TOKEN, rem), json_index + 5


    if json_index == len(json_str):
        return (END_JSON, None), json_index
    elif json_str[json_index] == '{':
        return (BEGIN_OBJECT, json_str[json_index]), json_index + 1
    elif json_str[json_index] == '}':
        return (END_OBJECT, json_str[json_index]), json_index + 1
    elif json_str[json_index] == '[':
        return (BEGIN_ARRAY, json_str[json_index]), json_index + 1
    elif json_str[json_index] == ']':
        return (END_ARRAY, json_str[json_index]), json_index + 1
    elif json_str[json_index] == ',':
        return (COMMA_TOKEN, json_str[json_index]), json_index + 1
    elif json_str[json_index] == ':':
        return (COLON_TOKEN, json_str[json_index]), json_index + 1
    elif json_str[json_index] == 'n':
        return read_null()
    elif json_str[json_index] == 't' or json_str[json_index] == 'f':
        return read_bool(json_str[json_index])
    elif json_str[json_index] == '"':
        return read_str(json_index)
    if json_str[json_index].isdigit():
        return read_num(json_index)


def tokenizer(json_str: str) -> list:
    """
    生成token序列
    :param json_str:
    :return:
    """
    json_index = 0
    tk, cur_index = token_parse(json_str, json_index)
    token_list = []
    generate_tokenlist(token_list, tk)
    while tk[0] != END_JSON:
        tk, cur_index = token_parse(json_str, cur_index)
        generate_tokenlist(token_list, tk)
    return token_list


def generate_token(tokentype: int, tokenvalue: str) -> tuple:
    """
    生成token结构
    :param tokentype: token的类型
    :param tokenvalue: token的值
    :return: 返回token
    """
    token = (tokentype, tokenvalue)
    return token


def generate_tokenlist(tokenlist: list, token: tuple) -> list:

    tokenlist.append(token)
    return tokenlist


def parse_json(tokenlist: list):

    def check_token(expected: int, actual: int):
        if expected & actual == 0:
            raise Exception('Unexpected Token at position %d' % json_index)

    def parse_json_array():
        """
        处理array对象
        :return: 处理json中的array对象
        """
        global json_index
        expected = BEGIN_ARRAY | END_ARRAY | BEGIN_OBJECT | END_OBJECT | NULL_TOKEN | NUMBER_TOKEN | BOOL_TOKEN | STRING_TOKEN

        while json_index != len(tokenlist):
            json_index += 1
            token = tokenlist[json_index]
            # token_type -> TokenEnum
            token_type = token[0]
            token_value = token[1]
            check_token(expected, token_type)

            # check through each condition
            if token_type == BEGIN_OBJECT:
                array.append(parse_json_object())
                expected = COMMA_TOKEN | END_ARRAY
            elif token_type == BEGIN_ARRAY:
                array.append(parse_json_array())
                expected = COMMA_TOKEN | END_ARRAY
            elif token_type == END_ARRAY:
                return array
            elif token_type == NULL_TOKEN:
                array.append(None)
                expected = COMMA_TOKEN | END_ARRAY
            elif token_type == NUMBER_TOKEN:
                array.append(int(token_value))
                expected = COMMA_TOKEN | END_ARRAY
            elif token_type == STRING_TOKEN:
                # print("array-------------array")
                array.append(token_value)
                expected = COMMA_TOKEN | END_ARRAY
            elif token_type == BOOL_TOKEN:
                token_value = token_value.lower().capitalize()
                array.append({'True': True, 'False': False}[token_value])
                expected = COMMA_TOKEN | END_ARRAY
            elif COMMA_TOKEN:
                expected = BEGIN_ARRAY | BEGIN_OBJECT | STRING_TOKEN | BOOL_TOKEN | NULL_TOKEN | NUMBER_TOKEN
            elif END_JSON:
                return array
            else:
                raise Exception('Unexpected Token at position %d' % json_index)

    def parse_json_object():
        """
        处理json对象
        :return:处理json中的json对象
        """
        global json_index
        expected = STRING_TOKEN | END_OBJECT
        key = None
        while json_index != len(tokenlist):
            json_index += 1
            token = tokenlist[json_index]
            token_type = token[0]
            token_value = token[1]
            # print("expected: ", expected, "token_type: ", token_type, "token_value: ", token_value)
            check_token(expected, token_type)
            if token_type == BEGIN_OBJECT:
                obj.update({key: parse_json_object()})
                expected = COMMA_TOKEN | END_OBJECT
            elif token_type == END_OBJECT:
                return obj
            elif token_type == BEGIN_ARRAY:
                # print("join array")
                obj.update({key: parse_json_array()})
                expected = COMMA_TOKEN | END_OBJECT | STRING_TOKEN
            elif token_type == NULL_TOKEN:
                obj.update({key: None})
                expected = COMMA_TOKEN | END_OBJECT
            elif token_type == STRING_TOKEN:
                pre_token = tokenlist[json_index - 1]
                pre_token_value = pre_token[0]
                # print(pre_token_value)
                if pre_token_value == COLON_TOKEN:
                    value = token[1]
                    obj.update({key: value})
               #      print("----------")
                    expected = COMMA_TOKEN | END_OBJECT
                else:
                    key = token[1]
                    expected = COLON_TOKEN
               #     print("+++++++++")

            elif token_type == NUMBER_TOKEN:
                obj.update({key: int(token_value)})
                expected = COMMA_TOKEN | END_OBJECT
            elif token_type == BOOL_TOKEN:
                token_value = token_value.lower().capitalize()
                obj.update({key: {'True': True, 'False': False}[token_value]})
                expected = COMMA_TOKEN | END_OBJECT
            elif token_type == COLON_TOKEN:
                expected = NULL_TOKEN | NUMBER_TOKEN | BOOL_TOKEN | STRING_TOKEN | BEGIN_ARRAY | BEGIN_OBJECT
            elif token_type == COMMA_TOKEN:
                expected = STRING_TOKEN
            elif token_type == END_JSON:
                return obj
            else:
                raise Exception('Unexpected Token at position %d' % json_index)
    array = []
    obj = {}
    global json_index
    if tokenlist[0][0] == BEGIN_OBJECT:
        return parse_json_object()
    elif tokenlist[0][0] == BEGIN_ARRAY:
        return parse_json_array()
    else:
        raise Exception('Illegal Token at position %d' % json_index)


if __name__ == "__main__":
    raw_data = input()
    jlist = tokenizer(raw_data)
    try:
        jdict = parse_json(jlist)
        print(jdict)
    except BaseException as result:
        print(result)

第2关:深度优先遍历目录

本关任务:深度优先递归遍历文件夹,如果是文件就直接输出当前文件绝对路径,如果是文件夹,就输出当前文件夹路径,然后接着遍历该子文件夹,直到指定文件夹被全部遍历完。

编程提示
  1. os.listdir返回的列表是无序的,需要对其进行排序后再进行递归遍历,保证输出结果的唯一性。
  2. 测试输出中的.gitkeep可以忽略,这是平台在每个目录下自带的一个文件
#使用深度优先遍历目录
from os import listdir
from os.path import join,isfile,isdir
def listDirDepthFirst(directory):
    """
    深度遍历算法遍历目录

    :param director: 需遍历的路径
    :return:无返回值,直接输出
    """
# *************begin************#
    if not isdir(directory):
        print(directory,'is not a directoryn or does not exist.')
        return
    for subPath in listdir(directory):
        path=join(directory,subPath)
        if isfile(path):
            print(path)
        elif isdir(path):
            print(path)
            listDirDepthFirst(path)

# **************end*************#  


#遍历当前目录下的test目录
listDirDepthFirst('./test')

第3关:广度优先遍历目录

本关任务:广度优先递归遍历文件夹,使用列表模拟队列。

#使用深度优先遍历目录
from os import listdir
from os.path import join,isfile,isdir
def listDirWidthFirst(directory):
    """
    广度遍历优先算法遍历目录

    :param director: 需遍历的路径
    :return:无返回值,直接输出
    """
# *************begin************#
    if not isdir(directory):
        print(directory,'is not a directory or does not exist.')
        return 
    dirs=[directory]
    while dirs:
        current=dirs.pop(0)
        for subPath in listdir(current):
            path =join(current,subPath)
            if isfile(path):
                print(path)
            elif isdir(path):
                print(path)
                dirs.append(path)


# **************end*************#  


#遍历当前目录下的test目录
path = input()
listDirWidthFirst(path)

第4关:os.walk遍历目录

本关任务:使用os.walk函数遍历目录

import os
def listDiroswalk(path):
    """
    使用os.walk遍历目录

    :param director: 需遍历的路径
    :return:无返回值,直接输出
    """
# *************begin************#
    if not os.path.isdir(path):
        print(path,'is not a directory or does not exist.')
        return
    list_dirs=os.walk(path)
    for root,dirs,files in list_dirs:
        for d in dirs:
            print(os.path.join(root,d))
        for f in files:
            print(os.path.join(root,f))
# **************end*************#  


#遍历当前目录下的test目录
path = input()
listDiroswalk(path)

第5关:遍历目录查找文件

本关任务:编写算法,在指定目录以及子目录中查找某文件是否存在。

相关知识

为了完成本关任务,你需要掌握:1.目录遍历算法,2.读文件操作。

目录遍历算法

可以采用深度遍历、广度遍历或使用os.walk模块对目录进行遍历

读文件操作

使用readlines函数逐行输出文件内容

判定文件是否存在目录中

使用一个标志位记录文件是否存在目录中

测试说明

平台会对你编写的代码进行测试:

测试输入: c:\pytest F.txt

输出: this is firstline this is second line this is third line

测试输入: c:\pytest E.txt

输出: E.txt does not exist.

测试输入: F.txt F.txt

输出: F.txt is not a directory or does not exist.

import os
def findfile(path,dstfile):
    """
    遍历目录中是否存在dstfile文件,如果存在输出该文件的内容,否则输出 dstfile does not exist.

    :param path: 需遍历的路径
    :dstfile: 需要查找的文件
    """
# *************begin************#
    if not os.path.isdir(path):
        print(f"{path} is not a directory or does not exist.")
        return
        
    file_found=False
    for root,dirs,files in os.walk(path):
        if dstfile in files:
            file_found=True
            file_path=os.path.join(root,dstfile)
            with open(file_path,'r',encoding='utf-8') as f:
                lines=f.readlines()
                for line in lines:
                    print(line.strip())
            break
    if not file_found:
        print(f"{dstfile} does not exist.")
# **************end*************#  
#遍历当前目录下的test目录
path = input()
file = input()
findfile(path,file)

第6关:读取文件内容

本关任务:编写一个能读取文件内容的函数。

编程要求

根据提示,在右侧编辑器补充代码,如文件存在,则输出文件信息,若文件不存在,则输出无法打开指定的文件!,若文件编码方案和打开指定编码方案不同,则输出指定了未知的编码!,若读取文件时解码错误,则输出读取文件时解码错误!

测试说明

平台会对你编写的代码进行测试:

测试输入: 致橡树.txt,utf-8

说明:致橡树.txt文件存在,编码方案encoding默认为utf-8 预期输出:

  1. 我如果爱你——
  2. 绝不像攀援的凌霄花,
  3. 借你的高枝炫耀自己;
  4. 我如果爱你——
  5. 绝不学痴情的鸟儿,
  6. 为绿荫重复单调的歌曲;
  7. 也不止像泉源,
  8. 常年送来清凉的慰藉;
  9. 也不止像险峰,
  10. 增加你的高度,衬托你的威仪。
  11. 甚至日光,
  12. 甚至春雨。
  13. 不,这些都还不够!
  14. 我必须是你近旁的一株木棉,
  15. 作为树的形象和你站在一起。
  16. 根,紧握在地下;
  17. 叶,相触在云里。
  18. 每一阵风过,
  19. 我们都互相致意,
  20. 但没有人,
  21. 听懂我们的言语。
  22. 你有你的铜枝铁干,
  23. 像刀,像剑,也像戟;
  24. 我有我红硕的花朵,
  25. 像沉重的叹息,
  26. 又像英勇的火炬。
  27. 我们分担寒潮、风雷、霹雳;
  28. 我们共享雾霭、流岚、虹霓。
  29. 仿佛永远分离,
  30. 却又终身相依。
  31. 这才是伟大的爱情,
  32. 坚贞就在这里:
  33. 爱——
  34. 不仅爱你伟岸的身躯,
  35. 也爱你坚持的位置,
  36. 足下的土地。

测试输入: tt.txt,utf-8 说明:tt.txt不存在,编码方案encoding默认为utf-8 预期输出: 无法打开指定的文件!

测试输入: 致橡树.txt,ajgfahajfhak; 说明:致橡树.txt存在,编码方案encoding为ajgfahajfhak 预期输出: 指定了未知的编码!

def file(name,encoding = 'utf-8'):
    '''
       读取文件内容,如文件存在,则输出文件信息,
       若文件不存在,则输出`无法打开指定的文件!`,
       若文件编码方案和打开指定编码方案不同,则输出`指定了未知的编码!`,
       若读取文件时解码错误,则输出`读取文件时解码错误!`
       :params name:文件名
       :params encoding:编码方案。默认为'utf-8'
       :return :无返回值,直接输出
       '''
    #        请在此处添加代码       #
    # *************begin************#
    try:
        with open(name,'r',encoding=encoding) as f:
            print(f.read())
    except(LookupError):
        print("指定了未知的编码!")
    except:
        print("无法打开指定的文件!")
    # **************end*************#

if __name__ == '__main__':
    name,encoding = input().split(',')
    file(name=name,encoding=encoding)

第7关:素数写入文件

本关任务:编写一个将1-9999之间的素数分别写入三个文件中(1-99之间的素数保存在a.txt中,100-999之间的素数保存在b.txt中,1000-9999之间的素数保存在c.txt中)。

编程要求

根据提示,在右侧编辑器补充代码,将1-99之间的素数保存在a.txt中,100-999之间的素数保存在b.txt中,1000-9999之间的素数保存在c.txt中。

from math import sqrt


def is_prime(n):
    """判断素数的函数"""
    assert n > 0
    for factor in range(2, int(sqrt(n)) + 1):
        if n % factor == 0:
            return False
    return True if n != 1 else False


def store():
    #         请在此处添加代码       #
    # *************begin************#
    with open("a.txt","w") as f:
        for i in range(2,100):
            if is_prime(i):
                f.write(str(i)+"\n")

    with open("b.txt","w") as f:
        for i in range(100,1000):
            if is_prime(i):
                f.write(str(i)+"\n")

    with open("c.txt","w") as f:
        for i in range(1000,10000):
            if is_prime(i):
                f.write(str(i)+"\n")

    # **************end*************#


第8关:输出文件目录

本关任务:遍历文件夹,采用深度优先遍历策略,以便输出要求的内容。

相关知识

为了完成本关任务,你需要掌握:1.os模块中相关文件目录操作。

from os import listdir
from os.path import join,isfile,isdir
def listDir(director):
    """
     遍历文件夹,如果是文件就直接输出当前文件绝对路径,
     如果是文件夹,就输出当前文件夹路径,
     然后接着遍历该子文件夹,直到指定文件夹被全部遍历完。

     :param director: 需遍历的路径
     :return:无返回值,直接输出
     """
    #        请在此处添加代码       #
    # *************begin************#
    if not isdir(director):
        print("no")
        return
    for x in listdir(director):
        temp=join(director,x)
        if isfile(temp):
            print(temp)
        elif isdir(temp):
            print(temp)
            listDir(temp)

    # **************end*************#


第9关:读写json文件

本关任务:编写一个能读写json文件的程序。

平台会对你编写的代码进行测试:

测试输入: 文件与异常/src/step4/book.txt

预期输出: [{'书名': 'python程序设计', '价钱': '39'}, {'书名': '数据结构', '价钱': '49'}, {'书名': 'C语言程序设计', '价钱': '42'}]

import json
def main(name):
 #        请在此处添加代码         #
 # *************begin************#
    with open(name,"r") as f:
        con=f.readline()
    print(con)
 # **************end*************#  
if __name__ == '__main__':
    name = input()
    main(name)

第10关:读取CSV文件1

本关任务:编写一个能读取csv文件的程序,将指定的文件按照要求的格式输出。

相关知识

为了完成本关任务,你需要掌握:1.csv模块

平台会对你编写的代码进行测试:在你的程序的当前目录下存在一个book.csv文件,读取该文件的内容,并输出要求的内容和格式。

import csv
def readcsv():
 #        请在此处添加代码         #
 # *************begin************#
    csvfile =open('book.csv','r',encoding='utf-8')
    csvreader=csv.reader(csvfile)
    for row in csvreader:
        print(row[0])
    csvfile.close()
 # **************end*************#
if __name__ == '__main__':
    readcsv()

第11关:读取CSV文件2

本关任务:编写一个能读取csv文件的程序,将指定的文件按照要求的格式输出。

import csv
def readcsv():
 #        请在此处添加代码         #
 # *************begin************#
    fc=open('book.csv','r',encoding='utf-8')
    lst=[]
    for line in fc:
        line =line.replace('\n','')
        lst.append(line.split(','))
    for i in range(1,len(lst)):
        print(lst[i])
    fc.close()
 # **************end*************#
if __name__ == '__main__':
    readcsv()

第12关:读取CSV文件3

本关任务:编写一个能读取csv文件的程序,将指定的文件按照要求的格式输出。

import csv
def readcsv():
 #        请在此处添加代码         #
 # *************begin************
    csvfile=open('book.csv','r',encoding='utf-8')
    csvreader=csv.DictReader(csvfile)
    lst=[]
    for i in csvreader:
        i=dict(i)
        lst.append(i)
    print(lst)
    csvfile.close()
 # **************end*************#



if __name__ == '__main__':
    readcsv()

第13关:统计文件中大写字母出现的次数

本关任务:编写程序,统计一个文本文件中出现的大写字母和它们出现的次数,并输出.

根据提示,在右侧编辑器补充代码,输出文件中出现的大写字母以及它们出现的次数。

测试说明

平台会对你编写的代码进行测试:

测试输入:test.txt; 预期输出: ('A', 8) ('B', 6) ('P', 2) ('L', 1) ('E', 1) ('C', 1)

测试输入:dream.txt; 预期输出: ('I', 3) ('D', 2) ('G', 1)

#统计大写字母出现的次数,并按照字母出现次数降序排序输出
def countchar(file):
# *************begin************#
    char_count={}
    with open(file,'r') as f:
        content=f.read()
    for char in content:
        if char.isupper():
            if char in char_count:
                char_count[char]+=1
            else:
                char_count[char]=1
    sorted_count=sorted(char_count.items(),key=lambda item: item[1],reverse=True)
    for item in sorted_count:
        print(item)

# **************end*************#  


file = input()
countchar(file)

第14关:统计文件中单词出现的次数,并输出出现次数高的前三个单词

本关任务:编写程序,统计一个文件中单词出现的次数,并输出出现次数最多的前3个单词。

根据提示,在右侧编辑器补充代码,输出出现次数最多的前三个单词。

测试说明

平台会对你编写的代码进行测试:

测试输入:dream.txt; 预期输出: (7, 'the') (7, 'of') (4, 'will')

测试输入:test.txt; 预期输出: (4, 'Apple') (3, 'Blue') (2, 'Big')

#统计一个文件中单词出现的次数,并输出出现次数最多的前3个单词
from collections import Counter

def countword(file):
    with open(file,'r') as f:
        text=f.read()
    words=text.split()
    word_counts=Counter(words)
    most_common_words=word_counts.most_common(3)
    for word,count in most_common_words:
        print(f"({count}, '{word}')")


file = input()
countword(file)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值