精华内容
下载资源
问答
  • 语法分析:自上而下分析 目录语法分析:自上而下分析知识背景计算海明校验码步骤一:计算校验码位数步骤二:确定校验组步骤三:计算校验码的值得出海明校验码利用海明校验码校验数据其他总结 知识背景 百度百科: ...

    语法分析:自上而下分析


    知识背景

    百度百科 “语法分析是编译过程的一个逻辑阶段。语法分析的任务是在词法分析的基础上将单词序列组合成各类语法短语,如“程序”,“语句”,“表达式”等等.语法分析程序判断源程序在结构上是否正确.源程序的结构由上下文无关文法描述.语法分析程序可以用YACC等工具自动生成。”

    语法分析在编译中也是一个比较很重要的环节,通常情况下语法分析可以分为自上而下分析和自下而上分析。
    本文主要介绍自上而下分析(从文法的开始符号出发)的大致框架和细节,并且附上我写的一些代码供大家讨论。首先我看了挺多的关于自上而下的分析,感觉这里一个老师的解释比较清晰,供大家参考 链接。接下来的内容,根据这里老师讲的一个大概框架,写一些我自己的理解,然后分析一下我的代码。

    要想进行自上而下分析,我们可以用LL(1)分析法来分析,而这个分析法主要有两种具体实现:递归分析法预测分析法,有可能其他地方不是这么叫的,但是分析的方法大同小异。
    在讨论两种方法前,首先要讨论一下一些预备知识:

    Q1:什么是自上而下分析法?自上而下分析的前提是什么?

    百度百科 “自上而下分析法是从文法开始符号开始,不断进行推导,直到推导所得的符号串与输入串相同为止。”

    简单来解释这句话:

    我们有一个既定的文法,和一个需要分析的符号串。接下来我们从文法的开始符号出发,反复地使用文法规定的一些产生式匹配符号串的每一个符号,直到所得的符号串和待分析的符号串相同,则为分析成功,反之匹配不成功。举个例子说明:
    G(E):
    E→aF
    F→b|c

    待分析的输入串:ab
    1
    从文法开始符号E出发,E→aF,a匹配成功后,指针指向F,找非终结符F的产生式合适的候选式 b匹配,于是匹配成功。

    想要对一个文法进行自上而下的分析,要消除文法的二义性,消除左递归,提取左公共因子,计算FIRST集合和FOLLOW集合,判断文法是否为LL(1)型文法,一个文法经过这些步骤,并且是LL(1)文法,则可以用LL(1)分析法的两个具体实现去分析。

    Q2:什么是分析过程中的回溯问题?
    从上面的例子我们可以看出,在我们碰到非终结符的时候要把非终结符用它对应的产生式的右部来代替,但是一个非终结符往往不止一个候选式(比如上面那个例子的F,F→b|c就有b和c两个选项),这个时候就会出现一个问题,如果我们选择候选式来替代非终结符的时候不能准确判断,这一次的替代是否能够正确推导出匹配的结果,一旦选择的候选式不能推导成功,就要返回上一步,换一个候选式进行推导,这就是“回溯”。例如上面那个例子,我们在拓展F的时候选择了c,会发现匹配失败,然后再返回上一步,选择另一个候选式b,才匹配成功。

    Q3:如何解决回溯的问题?
    实际上,含有回溯的分析过程并非不可取,只是会浪费很多的资源和时间,因此我们要想办法消除回溯,也就是争取让每一次选择候选式都选择正确的那一个。这就涉及到了下文要讲的FIRST、FOLLOW集合了。

    Q4:什么是文法中含有左递归?
    左递归分为直接左递归和间接左递归

    • 直接左递归
      举一个小例子G(E):E→Ea
      在这个文法中虽然只有一个产生式,但是对这个产生式进行构造语法树的时候会发现:
      2
      这个树会无限向下扩展,无法匹配结束。
    • 间接左递归
      举一个小例子G(E):
      3
      这个文法推导三次后会发现又回到了文法的开始符号又一次出现了,因此又进入循环,无法结束匹配,这就是间接左递归。

    Q5:如何解决文法含有左递归的问题?
    对于直接左递归,我们通常把它转换成右递归很好理解,举个小例子:
    G(E):E→Ea |b
    对于这个含有直接左递归的文法,将它转换成右递归的具体做法就是引入一个新的非终结符,通常我们用当前非终结符加 ’ 来表示,将文法改为
    G(E):
    E→bE’
    E’ →aE’|ε
    可以很容易地证明这两个文法是等价的。

    对于间接左递归,通常把非终结符带入来产生直接左递归,例如:
    G(E):
    4
    把S右部中的Q用Q的产生式代替,再把Q中的R用R的产生式代替,删除无关产生式后,就能得到一个含有直接左递归的文法:
    G(E): S→Sabc|abc|bc|c
    然后再将这个产生式按照直接左递归的处理方法进行消除左递归处理。

    更一般地,想要让程序自动地消除左递归,具体的做法如下:
    1.把文法的所有非终结符进行排序S = [‘A’,‘B’,…]
    2.做一个嵌套循环:
    其中S[k]为排在S[j]之后的非终结符,bunch_i为非终结符和终结符组成的串

    for j in range(len(s)):
            for k in range(j):
            	原产生式中:S[j]→S[k]bunch_1的S[k]用其对应的产生式代替
            	S[k]→bunch_2|bunch_3|...
            	推出:S[j]→bunch_2 bunch_1|bunch_3 bunch_1|...
            	如此,做完循环后该文法若有间接左递归,就将其转换成直接左递归了
            	消除直接左递归,具体做法见上文
    循环结束后删除无用产生式
    

    下面截取一些我写的消除左递归的代码进行讨论,完整源码下载请点击 下载

    获取每一条产生式的所有候选式:

                temp_split = [] # 将每一个产生式分割以便求的长度来进行分类讨论
                # 获取这一条产生式的所有'|'的索引值
                temp_or = []
                temp_push = []
                for q in range(len(lst[j])):
                    if lst[j][q] == '|':
                        temp_or.append(q)
                # 获取这一条产生式'→'的索引值
                temp_get = lst[j].index('→')
                # 转换成列表方便组合
                temp_push.append(temp_get)
                # 合并查找索引列表
                temp_search =  temp_push + temp_or
                # 把一个产生式以'→'和'|'为分隔符分割,将分割后的数据存储在嵌套列表temp_split里
                for m in range(len(temp_search)):
                    if len(temp_search) == 1:
                        temp_split_1 = [lst[j][temp_search[m] + 1:][:]]
                        temp_split = temp_split_1[:]
                    else:
                        if m == (len(temp_search) - 1):
                            temp_split.append(lst[j][temp_search[m] + 1:])
                        else:
                            temp_split.append(lst[j][temp_search[m] + 1:temp_search[m + 1]])
    

    间接左递归转换成直接左递归:

                change = [s[j],"→"]
                # change = []
                print("ts:",temp_split)
                for n in temp_split:
                    if "'" in n:
                        n[n.index("'") - 1] += "'"
                        n.remove("'")
                    try:
                        if n[0] == s[k]:
                            k_push = lst[k][:]
                            temp_z = []
                            for z in range(len(k_push)):
                                if k_push[z] == '|':
                                    temp_z.append(z)
                            for x in temp_z:
                                for c in n[1:]:
                                    k_push.insert(x,c)
                            for c in n[1:]:
                                if len(c) != 1:
                                    k_push.extend(c)
                                else:
                                    k_push.append(c)
                            change.extend(k_push)
                            change.append("|")
                        else:
                            if len(n) == 1:
                                change.append("".join(n))
                            else:
                                change.extend(n)
                                change.append("|")
                    except:
                        print("mark")
                lst[j] = change
                print("change1:",lst[j])
    

    Q6:什么是提取左公因子?
    类似数学上的提取公因式,把形如
    E→bunch_1bunch_2|bunch_1bunch_3|…|bunch_1bunch_n|其他开头不是bunch_1的候选式
    的产生式改写成 :
    E→bunch_1E’|其他开头不是bunch_1的候选式
    E’→bunch_2|bunch_3|…|bunch_n

    的形式

    有话说: 通常情况下,提取左公因子要反复进行,直到所有非终结符的FIRST集合两两不相交。

    提取左公因子的代码比较简单,完整代码见 链接

    Q7:什么是文法符号的FIRST集,非终结符的FOLLOW集,任意串的FIRST集?
    构造这些FIRST集和FOLLOW集的主要目的是为了消除回溯,也就是选择候选式的时候能够更加准确,当然,这些集合在别的地方也有用处。关于Q7,参见我的另外一篇文章:FIRST / FOLLOW集合

    Q8:什么是LL(1)型文法?如何判断文法是否为LL(1)型?
    若一个文法G为LL(1)文法,则应满足以下条件:
    1.文法不含有左递归
    2.文法中每一个非终结符产生式中每一个候选式的FIRST集两两不相交(可以反复提取左公因子来接近这个条件)
    3.如果文法中的每一个非终结符的FIRST集若含有ε,则每一个候选式的FIRST集和该非终结符的FOLLOW集不相交

    下面截取一些我写的判断文法是否为LL(1)文法的代码进行讨论,完整源码下载请点击 下载
    下面代码中temp_split为当前产生式的所有候选式的列表,例如E→a|b|c,temp_split = [[‘a’],[‘b’],[‘c’]]

    		for n in range(len(temp_split) - 1):
                for q in range(1,len(temp_split)):
                    if len(set(get_first_bunch(temp_split[n],temp_lst)) & set(get_first_bunch(temp_split[q],temp_lst))) != 0:
                        print("error.")
                        flag = 0
                        break
            for n in range(len(temp_split)):
                if 'ε' in get_first_bunch(temp_split[n],temp_lst):
                    if len(set(get_first_bunch(temp_split[n],temp_lst)) & set(get_follow(temp_lst)["".join(j[:j.index("→")])])) != 0 :
                        print("error.")
                        flag = 0
                        break
    

    Q9:什么是LL(1)分析法?
    使用LL(1)分析法的前提见Q1
    LL(1)分析法:
    假设当前要匹配的输入串符号为a

    for i in 每一个候选式:
    	if a in FIRST(i):
    		选择候选式
    if a not in 每一个候选式的FIRST集
    	if a in FOLLOW(当前非终结符) and ε in FIRST(每一个候选式):
    		选择ε
    	else:
    		error();
    

    下面就LL(1)分析法的两种具体实现方式进行分析。

    递归下降分析法

    递归下降分析法,顾名思义就是使用递归的思想去分析,具体的步骤:

    对于一个文法G,对其每一个非终结符U构造一个递归过程,一般的,以非终结符的名字来命名这个子过程。所有子程序构造完成后,对指定文法,运行文法开始符号对应的子程序,返回匹配结果。

    下面分析每一步的具体操作。

    内容一:根据文法生成子程序

    在实践这一部分的代码的时候,我想了挺久,没有思路,因为要构造指定文法的递归子程序,但在编码的时候,我们并不知道用户要输入的文法结构是怎么样的,所以这就产生了这么一个问题:如何用函数构造函数?实际上,如果我们能知道文法结构,那么就可以硬编码来生成对应的子程序。但是为了程序的良好拓展性,最后我用了这一方法:
    1.create_function.py运行后, 用户输入一个指定文法
    2.程序读取该文法的所有非终结符并且创建一个字典以所有非终结符作为key,其值为该非终结符对应的子程序的名称(一般和非终结符同名)
    3.根据子程序的一般结构,定义每一个子程序不同的部分(比如子程序名称)
    4.用python的文件操作,往新文件function.py中写入子程序的内容,包括必要的import,全局变量和每一个子程序,其中每一个子程序用一个循环来写入代码。

    有话说: 在编写写入新文件的代码的时候需要记得’\n’,或者按行写入。

    那么子程序的一般结构是什么呢?
    例如:对于一个产生式E→AC|BD|ε,word为当前读入的符号

    def E(...):
    	if word in FIRST(AC):
    		A(...)
    		C(...)
    	elif word in FIRST(BD):
    		B(...)
    		D(...)
    	elif word in FOLLOW(A):
    		不做其他操作
    	else:
    		error()
    

    具体代码举例分析,完整代码见 链接

    引入需要用到的其他文件里的方法,这里我引用了我之前写的求FIRST / FOLLOW集合的方法,这里的bunch就是要匹配的输入串,是在我们create这个子程序的时候由用户输入的,q为指针,用来指向当前匹配的符号。IP当初我用来检查每一个环节输出是否正确。

    import syntactic_parser_demo
    
    bunch = "q#"
    q = 0
    IP = bunch[0]
    

    获取当前匹配字符到word中,判断匹配是否结束

     	global q
        global IP
        try:
            word = bunch[q]
            print("当前处理符号串符号:",word)
            IP = word
        except:
            IP = "!"
            return
        if word == '#':
            return
    

    获取当前产生式的所有候选式,存在temp_split列表中,例如E→a|b|c,temp_split = [[‘a’],[‘b’],[‘c’]]

    	temp_or = []
        temp_push = []
        for k in range(len(parser)):
            if parser[k] == '|':
                temp_or.append(k)
        temp_get = parser.index('→')
        temp_push.append(temp_get)
        temp_search = temp_push + temp_or
        temp_split = []
        for m in range(len(temp_search)):
            if len(temp_search) == 1:
                temp_split = [parser[temp_search[m] + 1:]]
            else:
                if m == (len(temp_search) - 1):
                    temp_split.append(parser[temp_search[m] + 1:])
                else:
                    temp_split.append(parser[temp_search[m] + 1:temp_search[m + 1]])
    

    判断是否需要递归调用其他子程序。
    在这里我用eval(n[temp_n.index(j)])(i,lst_origin)来递归调用其他子程序,但实际上eval在某些场合需要谨慎使用。python中exec也可以执行一个字符串中的表达式例如:exec ("print('1')")

    有话说: exec的返回值始终为 None 。

    	finish = 0
        for n in temp_split:
            if word == "".join(n[0]):
                q += 1
            temp_n = n[:]
            if "'" in temp_n:
                temp_n[temp_n.index("'") - 1] += "'"
                temp_n.remove("'")
            if "'" in n:
                n[n.index("'") - 1] += '1'
                n.remove("'")
            if word in syntactic_parser_demo.get_first_bunch(temp_n,lst_origin):
                finish = 1
                for j in temp_n:
                    for i in lst_origin:
                        if "".join(i[:i.index('→')]) == j:
                            eval(n[temp_n.index(j)])(i,lst_origin)
                            break
                break
    

    获取FOLLOW集,判断第二个条件,判断第三个条件

        dict_origin = syntactic_parser_demo.get_follow(lst_origin)
        lst_follow_use = dict_origin["".join(parser[:parser.index('→')])]
        if word in lst_follow_use:
            finish = 1
        if finish == 0:
            error()
    
        return IP
    
    

    下面取一部分写入子程序的一些核心代码,完整代码见 链接

    这里的写入部分我是将要写入的所有代码整合成一个字符串,再写入文件。写入的内容,先按照某一个子程序的结构,写出一个子程序的例子,再根据这个例子来写入代码。

    # 创建相应的子程序并写入文件
        back = open("function.py","a",encoding = "UTF-8")
        back.seek(0)
        back.truncate()
    
        back.write("import syntactic_parser_demo\n\n")
        back.write("bunch = " + "\"" + bunch + "\"" + "\nq = 0\nIP = bunch[0]\n\n")
        for j in lst:
            if "'" in j[:2]:
                temp = "".join(j[0]) + "1"
            else:
                temp = "".join(j[0])
            content = "def " + temp + "(word,parse,lst_origin):\n"\
            + "    global q\n" + "    global IP\n" + "    try:\n"\
            + "        word = bunch[q]\n" + "        print(\"当前处理符号串符号:\",word)\n"\
            + "        IP = word\n" + "    except:\n" + "        IP = \"!\"\n"\
            + "        return\n" + "    if word == '#':\n" + "        return\n"\
            + "    temp_or = []\n" + "    temp_push = []\n" + "    for k in range(len(parse)):\n"\
            + "        if parse[k] == '|':\n" + "            temp_or.append(k)\n" + "    temp_get = parse.index('→')\n"\
            + "    temp_push.append(temp_get)\n" + "    temp_search = temp_push + temp_or\n" + "    temp_split = []\n"\
            + "    for m in range(len(temp_search)):\n" + "        if len(temp_search) == 1:\n"\
            + "            temp_split = [parse[temp_search[m] + 1:]]\n" + "        else:\n"\
            + "            if m == (len(temp_search) - 1):\n"\
            + "                temp_split.append(parse[temp_search[m] + 1:])\n" + "            else:\n"\
            + "                temp_split.append(parse[temp_search[m] + 1:temp_search[m + 1]])\n"\
            + "    finish = 0\n" + "    for n in temp_split:\n" + "        if word == \"\".join(n[0]):\n"\
            + "            q += 1\n" + "        temp_n = n[:]\n"\
            + "        if \"\'\" in temp_n:\n" + "            temp_n[temp_n.index(\"'\") - 1] += \"\'\"\n"\
            + "            temp_n.remove(\"\'\")\n" + "" + "        if \"\'\" in n:\n"\
            + "            n[n.index(\"\'\") - 1] += '1'\n"\
            + "            n.remove(\"\'\")\n"\
            + "        if word in syntactic_parser_demo.get_first_bunch(temp_n,lst_origin):\n"\
            + "            finish = 1\n"\
            + "            for j in temp_n:\n" + "                for i in lst_origin:\n"\
            + "                    if \"\".join(i[:i.index('→')]) == j:\n"\
            + "                        eval(n[temp_n.index(j)])(word,i,lst_origin)\n"\
            + "                        break\n" + "            break\n"\
            + "    dict_origin = syntactic_parser_demo.get_follow(lst_origin)\n"\
            + "    lst_follow_use = dict_origin[\"\".join(parse[:parse.index('→')])]\n"\
            + "    if word in lst_follow_use:\n" + "        finish = 1\n"\
            + "    if finish == 0:\n" + "        error()\n\n"\
            + "    return IP\n\n"
            back.write(content)
        back.write("def error():\n    print('error.')\n    return \n")
        back.close()
    

    5

    内容二:调用文法开始符号所对应的子程序

    接下来就是递归下降分析法的主程序部分,这部分比较简单,这里import function不能省略因为下面用的是eval来调用文法开始符号对应的子程序。

    import function
    
    def error():
        print("error.")
        return
    
    
    if __name__ == "__main__":
        lst_demo = [["E","→","T","E","'"],["E","'","→","+","T","E","'","|","ε"],["T","→","F","T","'"],
               ["T","'","→","*","F","T","'","|","ε"],["F","→","(","E",")","|","q"]]
        print("当前内置文法:",lst_demo)
    
        try:
            ip = eval("function." + lst_demo[0][0])(lst_demo[0],lst_demo)
            print("ip:",ip)
            if ip == '#':
                print("匹配文法成功")
            else:
                print("Error.")
        except:
            print("找不到子程序,即当前没有找到function.py或其为空文本,请先运行create_function.py创建.")
            n = input("按任意键退出.")
    
        n = input("按任意键退出.")
    

    至此,递归下降分析法就完成了,可以少量修改代码让用户输入文法和输入串来达到更好的交互性。
    6

    预测分析法

    预测分析法是LL(1)分析法的另一种实现方法,它不需要构造每一个子程序,而是通过一张表来关联非终结符和终结符,这张表就是预测分析表,预测分析表可以说是预测分析法的核心部分。

    内容一:构造预测分析表

    关于预测分析表的构造,参见我之前的一篇文章 构造预测分析表

    内容二:预测分析法主程序

    这里我们用一个栈来存放过程数据,主要步骤如下:
    1.获取栈顶的元素A,获取输入串目前指针指向的元素a
    2.若A = ‘#’ ,a = ‘#’ 则匹配成功
    3.若A = a 但是A和a不为’#’,则pop栈顶元素,输入串指针+1
    4.若A为非终结符,这查询预测分析表,把由A和a确定的产生式的右部从右往左依次压入到栈中,若右部是ε,那就不做操作
    5.查找预测分析表得到预设的出错字符则调用error()

    下面截取一些我写的代码进行讨论,完整代码见 链接

    主程序的一些预备工作,这里我用列表来代替实现栈的一些功能

    # 预测分析程序
    
    import lexical_analysis_table
    
    # 形参lst为所有产生式,bunch为待分析符号串
    def control(lst,bunch):
        table = lexical_analysis_table.get_table(lst) # 获取预测分析表
        print("预测分析表:",table)
        stack = [] # 工作栈
        point = 0 # bunch指针
        flag = True
        s = table[-2] # 非终结符列表
        l = table[-1] # 终结符列表
        print("非终结符列表:",s,"终结符列表:",l)
        count = 0
    

    有话说: 这里要获取非终结符列表和终结符列表,他们的顺序是和表中的产生式有关的。

    先把’#'压入stack中,再压入文法开始符号,然后获取输入串的第一个符号

    	stack.append('#')
        stack.append("".join(lst[0][:lst[0].index('→')]))
    
        temp_word = bunch[point]
    

    然后正式开始匹配,根据上面步骤中的方法,用代码实现

    while flag:
            count += 1
            remain_bunch = bunch[point:]
            top_stack_word = stack.pop()
            print("number:",count,"|stack:",stack,"|top_ele:",top_stack_word,"|剩余输入串:",remain_bunch)
            if top_stack_word in l and top_stack_word != '#':
                if top_stack_word == temp_word:
                    point += 1
                    temp_word = bunch[point]
                else:
                    print("error.栈顶终结符和待分析终结符不一致.")
                    flag = False
            elif top_stack_word == '#':
                if top_stack_word == temp_word:
                    flag = False
                    print("分析成功.")
                else:
                    print("error.栈和串没有同时结束分析.")
                    flag = False
            elif top_stack_word in s:
                # print("in s:",temp_word)
                one = s.index(top_stack_word)
                two = l.index(temp_word)
                use_p = table[one][two][:]
                # if use_p == 'ε':
                #     print("get a 'ε'")
                if "'" in use_p:
                    index = use_p.index("'")
                    use_p[index - 1] += "'"
                    use_p.remove("'")
                # print("ready:",use_p)
                while True:
                    if len(use_p) == 1:
                        pop_word_temp = use_p
                        if pop_word_temp == "!":
                            print("error.未在预测分析表中找到替代.")
                            break
                        else:
                            stack.append(pop_word_temp)
                    else:
                        pop_word_temp = use_p.pop()
                        if pop_word_temp == 'ε':
                            print("ε值处理.")
                        elif pop_word_temp != "→":
                            stack.append(pop_word_temp)
                        else:
                            break
    

    rst

    总结

    • 同步更新至CSDN,仅作实验记录之用。
    • 水平有限,文章有需要改正之处还望指出。
    展开全文
  • 动态网页 —— 逆向分析法 + 案例

    千次阅读 多人点赞 2021-05-10 17:01:37
    动态网页的爬取呢,主要有逆向分析法和模拟法。我们今天主要介绍逆向分析法,后面会重点介绍模拟法中selenium库的使用。 动态网页 一、动态网页概述 1.1 什么是动态网页 动态网页是基本的html语法规范与Python、...

    引入 : 本章主要讲解的是动态网页爬取的相关技术。动态网页的爬取呢,主要有逆向分析法和模拟法。我们今天主要介绍逆向分析法,后面会重点介绍模拟法中selenium库的使用。


    在这里插入图片描述

    动态网页

    一、动态网页概述

    1.1 什么是动态网页


    动态网页是基本的html语法规范与Python、Java、C#等高级程序设计语言、数据库编程等多种技术的融合,以期实现对网站内容和风格的高效、动态和交互式的管理。因此,从这个意义上来讲,凡是结合了HTML以外的高级程序设计语言和数据库技术进行的网页编程技术生成的网页都是动态网页。
    在这里插入图片描述
    这是在网上搜到的定义 ,那么通俗一点的说法是什么呢 ?就是 你要找的东西在网页源代码可能是不会出现的。


    1.2 动态网页的常用技术


    动态网页经常Ajax、动态HTML等相关技术实现前后台数据的交互。对于传统的Web应用,当我们提交一个表单请求给服务器,服务器接收到请求之后,返回一个新的页面给浏览器,这种方式不仅浪费网络带宽,还会极大地影响用户体验,因为原网页和发送请求后获得的新页面两者中大部分的HTML内容是相同的,而且每次用户的交互都需要向服务器发送请求,并且刷新整个网页。这种问题的存在催生出了Ajax技术。

    Ajax的全称是Asynchronous JavaScript and
    XML,中文名称为异步的JavaScript和XML,是JavaScript异步加载技术、XML以及Dom,还有表现技术XHTML和CSS等技术的组合。使用
    Ajax技术不必刷新整个页面,只需对页面的局部进行更新,Ajax只取回一些必需的数据,它使用SOAP、XML或者支持JSON的Web
    Service接口,我们在客户端利用JavaScript处理来自服务器的响应,这样客户端和服务器之间的数据交互就减少了,访问速度和用户体验都得到了提升。如注册邮箱时使用的用户名唯一性验证普遍采用的就是Ajax技术,服务端返回的数据格式通常为json或xml,而不是HTML格式。


    1.3 动态网页的判定方法

    静态网页 :

    静态网页是以.html、.htm、.html、.shtml、.xml作为后缀的网页。静态网页的内容是固定的,每个页面都是独立的页面不会根据浏览者的不同需求而改变。

    动态网页 :

    使用ASP 或PHP 或 JSP 等作为后缀的网页。动态网页以数据库技术为基础,可以大大降低网站维护的工作量。

    判定方法
    1.右键查看网页源代码,如果数据在网页中即说明是静态网页,否则是动态网页。
    2.也可使用Request.get()爬取,返回r.text。如果数据全部在文本里则是静态网页,否则是动态网页或者动态和静态结合的网页,部分数据在网页里,部分数据不在网页上。

    1.4 动态网页的爬取方法

    动态网页的爬取方法一般分为逆向分析法和模拟法。逆向分析法难度较高,通过拦截网站发送的请求,找出真正的请求地址,要求爬虫爱好者熟悉前端特别是JavaScript相关技术。模拟法是使用第三方库如Selenium模拟浏览器的行为,解决页面加载和渲染的问题。

    二、案例

    案例网址 :重庆名医堂
    在这里插入图片描述
    还是原来的操作 ,f12 查看源代码,注意圈红,这次式XHR ,具体情况要具体分析。
    观察! 格式式json格式!这里我们在解析的时候要转换成字典很好用!在这里插入图片描述

    import  requests
    import json
    import pymysql
    import  time
    def get_html(url,headers,time=10):  #get请求通用函数,去掉了user-agent简化代码
        try:
            r = requests.get(url, headers=headers,timeout=time)  # 发送请求
            r.encoding = r.apparent_encoding  # 设置返回内容的字符集编码
            r.raise_for_status()  # 返回的状态码不等于200抛出异常
            return r.text  # 返回网页的文本内容
        except Exception as error:
            print(error)
    out_list=[]
    def parser(json_txt):
        txt = json.loads(json_txt)
        global row_count
        row_count=txt["doctorCount"] #总行数
        for row in txt["doctors"]: #医生信息列表
            staff_name=row.get("STAFF_NAME") #医生姓名
            if staff_name is None:
                staff_name=""
            staff_type=row.get("STAFF_TYPE") #职称
            if staff_type is None:
                staff_type=""
            remark=row.get("STAFF_REMARK") #简介
            if remark is None:
                remark=""
            #简单清洗,去除掉简介中的html标签
            remark=remark.replace("<p>","").replace("</p>","")
            #去除空白字符
            remark=remark.strip()
            org_name=row.get("ORG_NAME") #所属医院
            org_name=org_name if org_name is not None else ""
            org_grade_name=row.get("ORG_GRADE_NAME")#医院等级
            org_grade_name = org_grade_name if org_grade_name is not None else ""
            good_at=row.get("GOOT_AT") #擅长领域
            good_at= good_at if good_at is not  None else ""
            row_list=(
                staff_name,
                staff_type,
                remark,
                org_name,
                org_grade_name,
                good_at
            )
            out_list.append(row_list)
    def save_mysql(sql, val, **dbinfo): #通用数据存储mysql函数
        try:
            connect = pymysql.connect(**dbinfo)  # 创建数据库链接
            cursor = connect.cursor()  # 获取游标对象
            cursor.executemany(sql, val)  # 执行多条SQL
            connect.commit()  # 事务提交
        except Exception as err:
            connect.rollback()  # 事务回滚
            print(err)
        finally:
            cursor.close()
            connect.close(if __name__ == '__main__':
        head = {
        "User-Agent": "Mozilla/5.0 (Windows NT 6.3; Win64; x64)\
                       AppleWebKit/537.36 (KHTML, like Gecko) \
                       Chrome/89.0.4389.82 Safari/537.36"
        } #设置用户代理,应对简单反爬虫
    
        #为了得到总共数据条数,先爬一次得到row_count放入全局变量
        page_size=10 #每页的数据行数
        url='https://www.jkwin.com.cn/yst_web/doctor/getDoctorList?areaId=42&depId=&hasDuty=&pageNo=1&pageSize=10'
        json_txt=get_html(url,head) #发送请求
        print(json_txt) #查看是否有数据
        parser(json_txt) #解析函数
        print(out_list) #查看是否有数据
        page=row_count//page_size  #总共页数 页面太多速度太慢,以5页列,6改为page即可爬所有页面
        for i in range(2,6):
            url="https://www.jkwin.com.cn/yst_web/doctor/getDoctorList?areaId=42&depId=&hasDuty=&pageNo={0}&pageSize={1}".format(i,page_size)
            json_txt=get_html(url,head) #发送请求
            parser(json_txt) #解析函数
        #解析完数据了,然后一次性批量保存到MySQL数据库
        parms = {                      #数据库连接参数
                  "host": "--",
                  "user": "root",
                  "password": "123456",
                  "db": "---",
                  "charset": "utf8",
                }
        sql = "INSERT into doctorinfo(staff_name,staff_type,remark,\
                    org_name,org_grade_name,good_at)\
                    VALUES(%s,%s,%s,%s,%s,%s)"  # 带占位符的SQL
        save_mysql(sql, out_list, **parms)  # 调用函数,注意**不能省略
    

    注意!要修改自己的数据库信息!
    在这里插入图片描述

    结果:在这里插入图片描述
    sql语句:

    CREATE TABLE `doctorinfo` (
      `staff_name` varchar(255) DEFAULT NULL,
      `staff_type` varchar(255) DEFAULT NULL,
      `remark` varchar(10000) DEFAULT NULL,
      `org_name` varchar(255) DEFAULT NULL,
      `org_grade_name` varchar(255) DEFAULT NULL,
      `good_at` varchar(255) DEFAULT NULL
    ) 
    

    remark 那里的长度 我是随意设的 ,因为第一次跑出来 跳了一个提示 是长度不够!
    我就加长设置了!在这里插入图片描述

    拜~

    展开全文
  • 软件测试方法_边界值分析法

    千次阅读 2019-10-06 21:43:08
    ①边界值分析法的介绍和概念 ②边界值分析法的原理和思想 ③单缺陷假设和多缺陷假设 ④边界值测试数据类型 ⑤内部边界值分析 ⑥各类边界值测试介绍 ⑦基于边界值分析方法选择测试用例的原则 ⑧边界值分析法的...

    目录:

    ①边界值分析法的介绍和概念

    ②边界值分析法的原理和思想

    ③单缺陷假设和多缺陷假设

    ④边界值测试数据类型

    ⑤内部边界值分析

    ⑥各类边界值测试介绍

    ⑦基于边界值分析方法选择测试用例的原则

    ⑧边界值分析法的实例分析

    1、边界值分析法的介绍和概念

    边界值分析是一种常用的黑盒测试方法,是对等价类划分方法的补充;所谓边界值,是指相对于输入等价类和输出等价类而言,稍高于其最高值或稍低于最低值的一些特定情况。边界值分析的步骤包括确定边界,选择测试用例两个步骤。

    根据大量的测试统计数据,很多错误是发生在输入或输出范围的边界上,而不是发生在输入/输出范围的中间区域。因此针对各种边界情况设计测试用例,可以查出更多的错误。所以,边界值分析法是一种很实用的黑盒测试用例方法,它具有很强的发现故障缺陷能力。

    2、边界值分析法原理和思想

    2.1边界值分析法的基本原理

    错误更可能出现在输入变量的极值附近。失效极少由两个(或多个)缺陷的同时发生引起的。

    2.2边界值分析法的基本思想

    选取正好等于,刚刚大于或刚刚小于边界的值作为测试数据,而不是选取等价类中的典型值或任意值作为测试数据。

    表示方法:最小值min,略高于最小值min+,正常值nom,略低于最大值max-,最大值max

    3、单缺陷假设和多缺陷假设

    单缺陷假设是边界值分析的关键假设。单缺陷假设指“失效极少是由两个或两个以上的缺陷同时发生引起的”。在边界值分析中,单缺陷假设即选取测试用例时仅仅使得一个变量取极值,其他变量均取正常值。

    多缺陷假设则是指“失效是由两个或两个以上缺陷同时作用引起的”,要求在选取测试用例时同时让多个变量取极值。

    4、边界值测试数据类型

    类型包括:数值、速度、字符、地址、位置、尺寸、数量、空间……

    边界值

    测试用例的设计思路

    字符

    起始-1个字符/结束+1个字符

    假设一个文本输入区域允许输入1个到255个 字符,输入1个和255个字符作为有效等价类;输入0个和256个字符作为无效等价类,这几个数值都属于边界条件值。

    数值

    最小值-1/最大值+1

    假设某软件的数据输入域要求输入5位的数据值,可以使用10000作为最小值、99999作为最大值;然后使用刚好小于5位和大于5位的 数值来作为边界条件。

    空间

    小于空余空间一点/大于满空间一点

    例如在用U盘存储数据时,使用比剩余磁盘空间大一点(几KB)的文件作为边界条件。

    以上类型的边界值应该在:最大/最小、首位/末位、上/下、最快/最慢、最高/最低、 最短/最长、 空/满等情况下用边界值作为测试数据

    5、内部边界值分析

    在多数情况下,边界值条件是基于应用程序的功能设计而需要考虑的因素,可以从软件的规格说明或常识中得到,也是最终用户可以很容易发现问题的。然而,在测试用例设计过程中,某些边界值条件是不需要呈现给用户的,或者说用户是很难注意到的,但同时确实属于检验范畴内的边界条件,称为内部边界值条件或子边界值条件。

    内部边界值条件主要有下面几种:

    51、数值的边界值检验:计算机是基于二进制进行工作的,因此,软件的任何数值运算都有一定的范围限制。

    范围或值

    位(bit)

    0 或 1

    字节(byte)

    0 ~ 255

    字(word)

    0~65535(单字)或 0~4294967295(双字)

    千(K)

    1024

    兆(M)

    1048576

    吉(G)

    1073741824

    5.2字符的边界值检验:在计算机软件中,字符也是很重要的表示元素,其中ASCII和Unicode是常见的编码方式。如下列出了一些常用字符对应的ASCII码值。

    字符

    ASCII码值

    空 (null)

    0

    空格 (space)

    32

    可输入的字符

    33~126

    0~9

    48~57

    A~Z

    65~90

    a~z

    97~122

    5.3其它边界值检验:在不同的行业应用领域,依据硬件和软件的标准不同而具有各自特定的边界值。如下列出部分手机相关的边界值

    硬件设备

    范围或值

    手机锂电池电压

    工作电压:3.6~4.2V;

    保护电压:2.5~3V不等

    手机正常使用温度

    -25°C~+60°C

    6、边界值测试介绍

    6.1基本边界值测试

    有n个输入变量,设计测试用例使得一个变量在数据有效区内取最大值、略小于最大值、正常值、略大于最小值和最小值。如下图所示,两个变量X1,X2。它们的有效取值区间分别为[c,d],[a,b]。

    image

    对于有n个输入变量的程序,基本边界值分析的测试用例个数为4n+1

    边界值测试分析采用了可靠性理论的单缺陷假设。

    优点:简便易行;生成测试数据的成本很低

    局限性:测试用例不充分;不能发现测试变量之间的依赖关系;不考虑含义和性质;

    结论:只能作为初步测试用例使用

    6.2健壮性测试

    健壮性是指在异常情况下,软件还能正常运行的能力。健壮性考虑的主要部分是预期输出,而不是输入。健壮性测试是边界值分析的一种简单扩展。除了变量的5 个边界分析取值还要考虑略超过最大值(max)和略小于最小值(min)时的情况。健壮性测试的最大价值在于观察处理异常情况,它是检测软件系统容错性的重要手段。如下图所示。

    PS:软件容错性的度量:从非法输入中恢复;健壮性有两层含义:容错能力和恢复能力

    image

    对于有n个输入变量的程序,健壮性测试的测试用例个数为6n+1

    6.3最坏情况测试

    最坏情况测试拒绝单缺陷假设,它关心的是当多个变量取极值时出现的情况。最坏情况测试中,对每一个输入变量首先进行包含最小值、略高于最小值、正常值、略低于最大值、最大值等5个元素集合的测试,然后对这些集合进行笛卡尔积计算,以生成测试用例。最坏情况测试将意味着更大工作量。如下图所示。

    image

    对于有n个输入变量的程序,最坏情况测试的测试用例个数为5^n

    最坏情况与基本边界值分析的比较

    • 基本边界值分析测试用例是最坏情况测试用例的真子集
    • 最坏情况测试显然更彻底
    • 最坏情况测试工作量大得多,变量函数的最坏情况测试会产生5的n次方个测试用例,边界值分析只产生4n+1个测试用例

    image

    6.4健壮性最坏情况测试

    健壮最坏情况假设对每一个变量首先进行最小值、略小于最小值的值、略高于最小值的值、正常值、最大值、略高于最大值的值、略低于最大值的值等7个元素的集合。然后对这些集合进行笛卡尔积运算,以生成测试用例。如下图所示。

    image

    对于有n个输入变量的程序,健壮最坏情况测试的测试用例个数为7^n

    6.5特殊值测试

    • 边界值分析假定n个变量是互相独立的,没有考虑这些变量之间的互相依赖关系;
    • 特殊值测试使用领域知识、使用类似程序的经验开发用例的特殊值。
    • 特点:最直观、最不一致、具有高度主观性
    • 特殊值测试特别依赖测试人员的能力
    • 虽然特殊值测试是高度主观性,但是能更有效地发现问题

    例如:2月28日、2月29日

    6.6随机测试

    • 随机测试的基本思想

    不是永远选取有界变量的最小值、略高于最小值、正常值、略低于最大值和最大值,而是使用随机数生成器选出测试用例

    • 随机测试的一种实现方法

    有界变量a≤X≤b值的一个VisualBasic应用程序生成的X,满足下式:

    X=Int(b-a+1)*Rnd+a

    函数Int返回浮点数的整数部分

    函数Rnd生成区间[0,1]内的随机数

    7、基于边界值分析方法选择测试用例的原则

    1)如果输入条件规定了值的范围,则应取刚达到这个范围的边界的值,以及刚刚超越这个范围边界的值作为测试输入数据。

    例如,如果程序的规格说明中规定:

    "重量在10公斤至50公斤范围内的邮件,其邮费计算公式为……"。作为测试用例,我们应取10及50,还应取10.01,49.99,9.99及50.01等。

    2)如果输入条件规定了值的个数,则用最大个数,最小个数,比最小个数少一,比最大个数多一的数作为测试数据。

    例如,一个输入文件应包括1~255个记录,则测试用例可取1和255,还应取0及256等。

    3)将规则1)和2)应用于输出条件,即设计测试用例使输出值达到边界值及其左右的值。

    例如,某程序的规格说明要求计算出"每月保险金扣除额为0至1165.25元",其测试用例可取0.00及1165.24、还可取一0.01及1165.26等。

    再如一程序属于情报检索系统,要求每次“最少显示1条、最多显示4条情报摘要”,这时我们应考虑的测试用例包括1和4,还应包括0和5等。

    4)如果程序的规格说明给出的输入域或输出域是有序集合,则应选取集合的第一个元素和最后一个元素作为测试用例。

    5)如果程序中使用了一个内部数据结构,则应当选择这个内部数据结构的边界上的值作为测试用例。

    6)分析规格说明,找出其它可能的边界条件。

    8、边界值分析法实例分析

    现有一个学生标准化考试批阅试卷,产生成绩报告的程序。其规格说明如下:程序的输入文件由一些有80个字符的记录组成,如右图所示,所有记录分为3组:

    image

    标题:这一组只有一个记录,其内容为输出成绩报告的名字。

    试卷各题标准答案记录:每个记录均在第80个字符处标以数字"2"。该组的第一个记录的第1至第3个字符为题目编号(取值为1一999)。第10至第59个字符给出第1至第50题的答案(每个合法字符表示一个答案)。该组的第2,第3……个记录相应为第51至第100,第101至第150,…题的答案。

    每个学生的答卷描述:该组中每个记录的第80个字符均为数字"3"。每个学生的答卷在若干个记录中给出。如甲的首记录第1至第9字符给出学生姓名及学号,第10至第59字符列出的是甲所做的第1至第50题的答案。若试题数超过50,则第2,第3……纪录分别给出他的第51至第100,第101至第150……题的解答。然后是学生乙的答卷记录。

    学生人数不超过200,试题数不超过999。

    程序的输出有4个报告:
        a)按学号排列的成绩单,列出每个学生的成绩、名次。
        b)按学生成绩排序的成绩单。
        c)平均分数及标准偏差的报告。
        d)试题分析报告。按试题号排序,列出各题学生答对的百分比。

    分别考虑输入条件和输出条件,以及边界条件。给出右表所示的输入条件及相应的测试用例。

    image

    转载于:https://www.cnblogs.com/whylaughing/p/5821898.html

    展开全文
  • 边界值分析法设计测试用例

    千次阅读 2017-07-06 20:45:00
    一、边界值分析法简介 1.定义: 边界值分析法就是对输入或输出的边界值进行测试的一种黑盒测试方法。通常边界值分析法是作为对等价类划分法的补充,这种情况下,其测试用例来自等价类的边界。 2.与等价划分的区别 1...

    一、边界值分析法简介

    1.定义:

    边界值分析法就是对输入或输出的边界值进行测试的一种黑盒测试方法。通常边界值分析法是作为对等价类划分法的补充,这种情况下,其测试用例来自等价类的边界。

    2.与等价划分的区别

           1)边界值分析不是从某等价类中随便挑一个作为代表,而是使这个等价类的每个边界都要作为测试条件。

           2)边界值分析不仅考虑输入条件,还要考虑输出空间产生的测试情况。

    3.边界值分析方法的考虑:

    长期的测试工作经验告诉我们,大量的错误是发生在输入或输出范围的边界上,而不是发生在输入输出范围的内部。因此针对各种边界情况设计测试用例,可以查出更多的错误。

    使用边界值分析方法设计测试用例,首先应确定边界情况。通常输入和输出等价类的边界,就是应着重测试的边界情况。应当选取正好等于,刚刚大于或刚刚小于边界的值作为测试数据,而不是选取等价类中的典型值或任意值作为测试数据。

    4.常见的边界值

           1)对16Bit的整数而言,32767和32768是边界

           2)屏幕上光标在最左上、最右下位置

           3)报表的第一行和最后一行

           4)数组元素的第一个和最后一个

           5)循环的第0次、第1次和倒数第2次、最后一次

    5.边界值分析

           1)边界值分析使用与等价类划分法相同的划分,只是边界值分析假定错误更多地存在于划分的边界上,因此在等价类的边界上以及两侧的情况设计测试用例。

    例:测试计算平方根的函数

    输入:实数

    输出:实数

    规格说明:当输入一个0或比0大的数的时候,返回其正平方根;当输入一个小于0的数时,显示错误信息“平方根非法,输入值小于0”并返回0;库函数printLine可以用来输出错误信息。

           2)等价类划分:

              i.              可以考虑做出如下划分:

    A、输入(i)<0 和(ii)>=0

    B、输出(a)>=0和(b)Error

            ii.              测试用例有两个

    A、输入4,输出2.对应(ii)和(a)。

    B、输入10,输出0和错误提示。对应与(i)和(b)

           3)边界值分析

    划分(ii)的边界为0和最大正实数;划分(i)的边界为最小负实数和0.由此得到一下测试用例:

           A、输入{最小负实数}

           B、输入{绝对值很小的负数}

           C、输入0

           D、输入{绝对值很小的正数}

           E、输入{最大正实数}

           4)通常情况下,软件测试所包含的边界检验有几种类型:数字、字符、位置、重量、大小、速度、方位、尺寸、空间等。

           5)相应地,以上类型的边界值应该在:最大/最小、首位/末位、上/下、最快/最慢、最高/最低、最短/最长、空/满等情况下。

           6)利用边界值作为测试数据

    边界值

    测试用例的设计思路

    字符

    起始1个字符/结束+1个字符

    假设一个文本输入区域允许输入1个到255个字符,输入1个和255个字符作为有效等价类;输入0个和256个字符作为无效等价类,这几个数值都属于边界条件值

    数值

    最小值1/最大值+1

    假设某软件的数据输入域要求输入5位的数据值,可以使用10000作为最小值、9999作为最大值;然后使用刚好小于5位和大于5位的数值作为边界条件。

    空间

    小于空余空间一点/大于满空间一点

    例如在用U盘存储数据时,使用比剩余磁盘空间大一点(几KB)的文件作为边界条件

           7)内部边界值分析

    在多数情况下,边界值条件是基于应用程序的功能设计而需要考虑的因素,可以从软件的规格说明或常识中得到,也是最终用户可以很容易发现问题的。然而,在测试用例设计过程中,某些边界值条件是不需要呈现给用户的,或者说用户是很难注意到的,但同时确实属于检验范畴内的边界条件,称为内部边界值条件或子边界值条件。

    内部边界值条件主要有下面几种:

    1)数值的边界值检验:计算机是基于二进制进行工作的,因此,软件的任何数值运算都有一定的范围限制。

    范围或值

    位(Bit)

    0或者1

    字节(byte)

    0~255

    字(Word)

    0~65535(单字)或0~4294967295(双字)

    千(K)

    1024

    兆(M)

    1048576

    吉(G)

    1073741824

    2)字符的边界值检验:在计算机软件中,字符也是很重要的表示元素,其中ASCII和Unicode是常见的编码方式。下表中列出了一些常用字符对应的ASCII码值。

    字符

    ASCII码值

    字符

    ASCII码值

    空(Null)

    0

    A

    65

    空格(Space)

    32

    a

    97

    斜杠(/)

    47

    z

    122

    0

    48

    Z

    90

    冒号(:)

    58

    单引号(’)

    96

    @

    64

      

    3)其它边界值检验

    6.基于边界值分析方法选择测试用例的原则

    1. 如果输入条件规定了值的范围,则应取刚达到这个范围的边界的值,以及刚刚超越这个范围的边界的值作为测试输入数据。

    例如,如果程序的规格说明中规定:“重量在10公斤至50公斤范围内的邮件,其邮费计算公式为。。。。。。”,作为测试用例,我们应采取10及50,还应取10.01,49.99,9.99,50.01等

    2. 如果输入条件规定了值的个数,则用最大个数,最小个数,比最小个数少一,比最大个数多一的数作为测试数据。

    例如,一个输入文件应包括1~255个记录,则测试用例可取1和255,还应取0、256等。

    3. 将规则1和2应用于输出条件,即设计测试用例使输出值达到边界值及其左右的值。

    例如,某程序的规格说明要求计算出“每月保险金扣除额为0~1165.25元”,可取0.00,1165.24,0.01,1165.26等。

    再如一程序属于情报检索系统,要求每次“至少显示1条,最多显示4条情报摘要”,这时我们应考虑的测试用例应包括1,4,0,5等。

    4. 如果程序的规格说明给出的输入域或输出域是有序集合,则应选取集合的第一个元素和最后一个元素所谓测试用例。

    5. 如果程序中使用了一个内部数据结构,则应当选择这个内部数据结构的边界上的值作为测试用例。

    6. 分析规格说明,找出其它可能的边界条件。

    参考:http://www.cnblogs.com/sunshine2016/p/5577645.html

    转载于:https://www.cnblogs.com/zhangwuji/p/7128274.html

    展开全文
  • 层次分析法原理和matlab代码实现

    千次阅读 多人点赞 2020-04-12 22:30:09
    笔记来自清风老师的数学建模系列课程,课程链接:层次分析法 层次分析法例题,IMMC2020https://blog.csdn.net/yanyanwenmeng/article/details/104907412 1. 指标选择途径 (1)题目背景 (2)中国知网、百度学术...
  • 测试用例设计方法-边界值分析法

    千次阅读 2017-09-16 19:00:00
    边界值分析法 定义:边界值分析法就是对输入或输出的边界值进行测试的一种黑盒测试方法。通常边界值分析法是作为对等价类划分法的补充,这种情况下,其测试用例来自等价类的边界。 与等价类区别: 1)边界值分析...
  • 边界值分析:1)边界值分析使用与等价类划分相同的划分,只是边界值分析假定错误更多地存在于划分的边界上,因此在等价类的边界上以及两侧的情况设计测试用例。 例:测试计算平方根的函数 输入:实数 输出:...
  • 词法语法语义分析程序

    千次阅读 2014-06-05 10:01:47
    选择部分C语言的语法成分或选择简单语言,采用递归下降的语法制导翻译...内容:设计并实现一个一遍扫描的词法语法语义分析程序,将多条简单赋值语句翻译成后缀式或三地址代码,要求有一定的出错提示和错误恢复功能。
  • 图中定义了该HTML文档的字符编码。 定义了网页的标题为Python。 基本标签页: 开发者工具 爬虫作业中,最重要的一步就是提取数据。 我们可以根据HTML结构来分析页面元素进行提取,也可以根据正则表达式提取对应的...
  • x264源代码简单分析编码器主干部分-1

    万次阅读 多人点赞 2015-05-11 17:10:51
    本文分析x264编码器主干部分的源代码。“主干部分”指的就是libx264中最核心的接口函数——x264_encoder_encode(),以及相关的几个接口函数x264_encoder_open(),x264_encoder_headers(),和x264_encoder_close()。...
  • 字符编码: UTF8 和 ANSI 的区别分析

    千次阅读 2018-03-28 17:15:00
    字符编码是计算机技术的基石,想要熟练使用计算机,就必须懂得一点字符编码的知识。1. ASCII码我们知道,在计算机内部,所有的信息最终都表示为一个二进制的字符串。每一个二进制位(bit)有0和1两种状态,因此八个...
  • 数据分析-内容整理

    千次阅读 2018-03-21 18:02:14
    一、认识数据分析1.数据分析是指用合适的统计分析方法对收集来的数据进行分析,将这些大量的数据进行汇总,并做成可以被人们消化和理解的资料,从中提取有用的信息。2.数据分析的基本步骤(6个,缺一不可,相辅相成...
  • CMS中文编码问题分析及解决方案

    千次阅读 2004-11-10 23:58:00
    CMS中文编码问题分析及解决方案开题注: 有意见认为采用UTF-8编码将解决一切语言编码问题。我不同意这种意见: 其一对于中文用户,简体和繁体用户不习惯江两种编码字混排阅读;其二,目前大量网站采用GB/BIG5编码,而...
  • 字符编码的前世今生

    千次阅读 2017-09-18 17:24:07
    前言很多程序员对字符编码不太理解,虽然他们大概知道 ASCII、UTF8、GBK、Unicode 等术语概念,但在写代码过程中还是会遇到各种奇怪的编码问题,在 Java 中最常见的是乱码,而 Python 开发中遇到最多的是编码错误,...
  • 科普文章-另一个视角解读计算机编码(修订版)

    万次阅读 多人点赞 2017-06-17 17:59:55
    我不知道本文该作为原创发布还是作为转载发布,因为本文是《另一个视角解读计算机编码-补码编码》的“排版后的版本”,内容几乎没有变,除了增加了一系列的图解。 后来想了下,还是作为原创吧,毕竟《另一个视角...
  • 前言:之前的文章(高维数据中特征筛选方法的思考总结——单变量分析筛选)中,对单变量分析筛选变量进行了初步考量,本文将进一步总结多变量分析筛选。由于本文多处摘录网上的博客,只是进行了归纳整理,因此...
  • STM32 TIM 编码器模式采集编码器信号

    千次阅读 2019-10-26 10:22:25
    对于常用增量式编码器,光学编码器,采用带槽圆盘,一侧是发射光线的发射端,而光电晶体管在相对的一侧。当圆盘转动时,光程被阻断,得到的脉冲指示轴的转动和方向。通常的说法是1000线的编码器,即转一圈会产生1000...
  • 采用简化原型进行需求分析

    千次阅读 2004-12-27 22:48:00
    常用的软件需求分析方法有面向数据流的结构化分析方法、面向数据结构的Jackson方法、面向对象的方法和原型等。原型由于改变了系统的分析、设计和实现三个顺序阶段的观点[2],改变了传统的自顶向下的开发模式,...
  • 字符编码ASCII,Unicode和UTF-8

    千次阅读 2015-01-08 15:50:03
    http://blog.csdn.net/pipisorry/article/details/42387045字符编码介绍文本...实际上,从屏幕上的每一块文本都是以某种字符编码(character encoding)的方式保存的。粗略地说就是,字符编码提供一种映射,使屏幕上显示
  • 二进制(1):无符号编码和补码编码

    千次阅读 2016-05-25 19:08:15
    这里分析一下无符号编码,既是C语言中的unsigned int, 与补码编码,C语言中的 int。通过五个方面进行学习:1,将位模式转换为两种编码格式下的值的过程的函数缩写,2,位向量在两种编码格式下的取值范围,3,位向量...
  • DNA编码

    千次阅读 2017-12-27 14:42:19
    DNA编码的学习—-笔记1 虽然一万个不想学这个东西,但还是要先了解一些。...主要讲了DNA计算相关的内容。 首先说了DNA为什么出现,分子水平的研究成熟,数学上很多NP-hard问题传统计算机难以有效解决,
  • 计算机各种编码

    千次阅读 2015-04-30 10:13:17
    编码有几种 ,计算机最初是在美国等国家发明的 所以表示字符只有简单的几个字母只要对字母进行编码就好 我们标准码 iso-8859-1 这就是一个标准 但是后来计算机普及了 于是就中国要使用计算机了 但是机器不认
  • 词法分析

    千次阅读 2016-09-11 15:46:19
    执行词法分析的程序称为词法分析器。本章中,了解词法分析器的功能和输出形式,熟练掌握词法分析器设计的原理和方法,能够以转换图为工具使用某种语言的编写并调试一个扫描器。在正确理解正规表达式与有限自动机的...
  • Airbnb前端编码规范总结

    万次阅读 2016-10-16 21:55:48
    遵循编码规范和使用语法检测,可以很好的提高代码的可读性,可维护性,并有效的减少一些编码错误,这里学习的是著名的...代码检查是一种静态的分析,常用于寻找有问题的模式或者代码,并且不依赖于具体的编码风格。Ja
  • 块截断编码图像压缩技术

    千次阅读 2020-10-04 03:20:19
    论文先介绍了当前流行的图像压缩技术,重点介绍块截断编码技术,先从理论上介绍块截断编码原理,块截断编码是一种有效、快速的数字图像压缩技术,作为一种经典的图像压缩编码,块截断编码技术的实时性很强。...
  • Unicode字符编码标准

    千次阅读 2018-08-16 16:46:05
    1. 编码知识  1.1 文本和字符  在计算机程序中或者数据文件里,文本(text)是作为数字序列存储的。序列中的数字是具有不同大小、取值和解释的整数。如何解释这些整数是由字符集(character set)、编码(encoding...
  • 编码规范——华为篇

    万次阅读 多人点赞 2019-03-20 14:16:48
    编码规范很重要,其实他直接影响到了代码迭代更新的效率和出问题的概率。以下为本人对网上广为流传的华为编码规范的个人总结。(ps:其中有几个原则实在是精辟的不能再精辟了,当然也有一些存在疑惑,还希望各位大佬...
  • 内容运营是指基于内容的策划、编辑、发布、优化、营销等一系列工作,主要集中在互联网、媒体等以内容为主的行业领域。内容运营根据内容生产方式的不同可分为UGC、PGC和OGC三种。 UGC(User-generated Content),...
  • 字符编码的概念及字符编码的探测

    千次阅读 2014-01-06 19:21:31
    由此产生了使用多字节字符来表示的办法,比如GB编码的汉字。 但多字节带来的一个显著不便就是多字节字符在处理的时候不太方便。比如文本编辑的时候,中英文混排,光标移动、汉字删除时会出现半个汉字的问题。 为了...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 77,124
精华内容 30,849
关键字:

内容分析法怎么编码