[ZOJ 1116 ] [ POJ 1911 ] A Well-Formed Problem

ZOJ:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=1116

題目大意:

(對XML沒有了解,只是按照字面意思理解了一下題意)

<name>與</name>這樣有起始結束聲明的,name稱爲tag

<order/>是empty element, 不需要end-tag

第一行<?xml version="1.0"?>不算文檔的element

<zip-code format="PLUS4">10001-0001</zip-code>這裏的format是zip-code的屬性

一個well-formed document要滿足下面幾條:

1、只有一個element不嵌套在別的element裏,例如例子中的"customer" 
2、嵌套正確,不是<order/>那樣的,如<name>與</name>要完整配對嵌套
3、如<name>與</name>這樣的聲明名字要配對
4、一個tag最多一個屬性
5、不遞歸調用,如address element裏不能調用address
6、有名字的屬性,比如上面的format,要有對應的值

注意大小寫不同,如<Address>和<address>應該認爲是不同的



輸入:

每組數據第一行是 "<?xml version="1.0"?>"。

"<?end?>" 表示全部輸入的結束(只是在本題中用來標記輸入結束)

輸入保證:

 "<?xml version="1.0"?>"會且僅會在第一行出現

element和屬性只用數字、字母和短線"-"表示

XML註釋不出現

屬性的值一定會放在“”裏



輸出

"well-formed"或者"non well-formed"



解題思路:

字符串處理,主要用到棧和集合。

每次讀入到”<“的時候,開始讀取tag和attribute,同時判斷<>裏頭的內容有沒有問題,比如"/"出現的位置和次數有沒有問題,屬性的表達有沒有問題等。之後就只要進行一些判斷即可。下面是針對well-formed document的各條件的解決方法:

1、針對“只有一個element不嵌套在別的element裏,例如例子中的"customer" ”

設置bool root=false; 當棧空且有入棧操作時root=true;當root=true且在棧空情況下有入棧操作時返回non well-formed

2、針對“嵌套正確,不是<order/>那樣的,如<name>與</name>要完整配對嵌套”

棧,非類似<order/>時入棧,入棧忽略屬性,出棧時與棧頂元素

3、針對“如<name>與</name>這樣的聲明名字要配對”

同上

4、針對“一個tag最多一個屬性”

若在<>裏讀到""(輸入保證如果有屬性,其值一定包括在""裏), 則之後如果再出現非空字符,返回non well-formed

5、針對“不遞歸調用,如address element裏不能調用address”

設置set<string>類型,存放棧內元素,入棧前判斷set裏是否有相同tag,如果是,返回non well-formed

6、針對“有名字的屬性,比如上面的format,要有對應的值”

在<>內如果讀到空格,空格後面有字符,則必須有緊跟的="XXX"


源代碼:

又吐血了……”狗狗搞完40題“裏的代碼又好短,淚奔了,爲什麼每次寫蘑菇題我都要寫得很長╮(╯▽╰)╭

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cctype>
#include <string>
#include <set>
#include <stack> 
#include <iostream>
#include <algorithm>
using namespace std;
#define ERROR non=true;return

set<string> used;
stack<string> s;
bool non, root;

bool gettag(char* &ch, string &tag, bool &end, bool &empty)
// 讀到"<"觸發gettag, 函數結束後">"已讀過 
{
    int p1, p2, p3, p4;
    string attribute;
    
    end=false, empty=false;
    tag=attribute="";
    
    ch++;                                   //get tag
    if (*ch=='/'){end=true;ch++;}
    while (isalnum(*ch) || *ch=='-')      
    {
        tag+=*ch;
        ch++;
    }
    while (isspace(*ch)) ch++;
    if (*ch=='>')                            //end of tag?
        return 1;
    if (*ch=='/')
    {
        int cal=0;
        ch++;
        while (*ch!='>'){cal++;ch++;}
        if (cal>0) return -2;
        if (end) return -1;
        else empty=true;
    }
    while (isalnum(*ch) || *ch=='-' || *ch=='.' || *ch=='\"' || *ch=='=')        //get attribute
    {
        attribute+=*ch;
        ch++;
    }
    if (attribute.length()>0)
    {
        p1=attribute.find("=", 0);      if (p1==-1) return -3;
        p2=attribute.find("\"", 0);     if (p2<p1) return -4;
        p2=attribute.find("\"", p1+1);  if (p2==-1) return -5;
        p3=attribute.find("\"", p2+1);  if (p3==-1 || p3==p2+1) return -6;   //empty value
        p4=attribute.find("\"", p3+1);  if (p4!=-1) return -7;               //extra "
        p4=attribute.find("=", p1+1);   if (p4!=-1) return -8;               //extra =
    }
    while (isspace(*ch)) ch++;
    if (*ch=='>') return 1;
    if (*ch=='/')
    {
        int cal=0;
        ch++;
        while (*ch!='>'){cal++;ch++;}
        if (cal>0) return -10;
        if (end) return -9;
        else empty=true;
    }
    while (*ch!='>'){
        ch++;
        if (!isspace(*ch) && *ch!='>') return -11;
    }
    return 1;
}

void solve(char *ch)
{
    bool end, empty;
    string tag;
    int tmp;
    while (!non && *ch!='\0')
    {
        if (*ch=='<')
        {
            tmp=gettag(ch, tag, end, empty);
            if (tmp==1)
            {
                if (end && empty){
                    ERROR;
                }
                if (empty && used.count(tag)>0){
                    ERROR;
                }
                else if (!empty && !end)
                {
                    if (used.count(tag)>0){
                        ERROR;
                    }
                    if (s.empty())
                    {
                        if (root){ERROR;}
                        else root=true;
                    }
                    used.insert(tag);
                    s.push(tag);
                }
                else if (!empty && end)
                {
                    if (s.empty() || s.top()!=tag){
                    ERROR;
                }
                    used.erase(tag);
                    s.pop();
                }
            }
            else{ERROR;}
        }
        else ch++;
    }
}

int main()
{
    string tag, attribute;
    bool firstdata=true;
    bool end, empty;
    char buf[65536];
    do{
        while (gets(buf)!=NULL && strcmp(buf, "<?xml version=\"1.0\"?>")!=0
                && strcmp(buf, "<?end?>\n")!=0)
        {
            solve(buf);
        }
        if (strcmp(buf, "<?xml version=\"1.0\"?>")==0)
        {
            if (!firstdata)
            {
                if (non || !s.empty()) printf("non well-formed\n");
                else printf("well-formed\n");
            }
            else firstdata=false;
            non=false;
            root=false;
            used.clear();
            while (!s.empty()) s.pop();
        }
    }while (strcmp(buf, "<?end?>")!=0);
    if (non || !s.empty()) printf("non well-formed\n");
    else printf("well-formed\n");
    return 0;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章