본문 바로가기

알고리즘/HackerRank

[HackerRank] Attribute Parser

https://www.hackerrank.com/challenges/attribute-parser/problem

 

Attribute Parser | HackerRank

Parse the values within various tags.

www.hackerrank.com

문제 풀이)

1. 새로운 태그 생성

 

    - tag 이름 찾기

    - 속성 이름 찾기

    - 속성에 해당하는 값 찾기

 

    < tag > 

 

    tag이름의 경우 <tag1 name = "Name1"> 의 형태처럼 빈칸이 나올때까지 찾아도 되겠지만,

   

    속성 값이 없는 경우, 즉 <tag1>와 같은 값으로 들어올 때는 빈칸이 아닌 '>'까지 조사해주어야 한다.

 

    따라서 인덱스 1부터 문자가 ' ', '>'가 아닐 때까지가 tag임을 알 수 있다.

 

    < 속성, 값 >

 

    속성과 속성에 해당하는 값의 경우, 이 둘은 한 세트로 나온다. 문제에서 HRML은 논리적으로 맞는 문장만

 

    나옴을 보장했으니, 한 세트로 나오지 않는 경우는 생각하지 안해도 되는 것 같다.

 

    처음에는 속성, 속성이 나온 후라면 값을 찾아주는 형태로 하면 된다. 쉽게 말해 flag값을 두어 0일 경우엔

 

    속성이라고 간주하고 문자열을 찾고, 1일 경우엔 값이라고 간주하고 문자열을 찾으면 된다.

 

    각 속성과 값은 여러 개가 나올 수 있으므로, tag라는 class를 만들어 vector에 push해주는 형태로 만들었다.

 

    주의해야할 것은 <tag1 name = "Name1" value = "Value1"> 과 같은 문장이 있을 때, 속성을 찾은 뒤

 

    값을 찾을 때이다. 현재 인덱스로부터 가장 가까운 " 를 찾아, 그 이후로부터 다시 "가 나올 때까지를

 

    값으로 생각하면 된다. 다시 속성이 나올 수 있으므로, 인덱스를 1이 아닌 '2'를 증가시켜주여야 함을 잊지 말자.

 

    ( " 이후에 빈칸이 나오고 나서 문자가 나오기 때문 )

 

    < tag 추가하기 >

 

    위와 같이 태그, 속성, 값을 찾아 새로 만든 tag 클래스에 추가해주었다면, 이제 이 태그를 어디에 추가할 지를

 

    고려해야 한다. 이는 stack을 이용하여 구현했다. <tag ~ > 와 같이 tag가 추가되는 형태라면 stack에 push를

 

    해주고, </tag> 와 같이 닫히는 형태라면 stack에 pop을 해주었다.

 

    태그가 추가될 때 stack이 empty 상태가 아니라면 새로 추가되는 태그의 경우 최상위 태그가 아니라는 것이고,

 

    따라서 stack.top()에 있는 태그 클래스에 선언해둔 vector<tag*> 에 새로운 태그를 push해주었다.

 

2. query 문 처리하기

 

    - . 혹은 ~ 가 아니라면 태그 이름이다.

 

    말 그대로 .이나 ~가 아닌 경우 태그 이름으로 간주하고 string 변수에 넣어주자.

 

    이후에 .이나 '~'의 경우 string 변수에 넣어둔 태그 이름을 이용하여 tag를 찾아준다.

 

    만약 tag이름을 찾지 못했다면 Not Found! 를 출력해준다.

 

    '.'이었을 경우 반복하고, '~'의 경우 이제 속성이름이 나온다는 것이므로 속성이름을 빼내어

 

    태그 이름을 통해 찾은 tag의 속성 목록에 존재하는 지 찾아보고 존재한다면 값을 출력,

 

    존재하지 않는다면 Not Found!를 출력해주면 된다.

 

3. 주의    

 

    - 태그 이름은 'tag' + @ 가 아니라, 'a' 와 같이 tag가 붙지 않아도 된다.

 

    - 속성과 값은 여러 개일수도, 없을 수도 있다.

    

    - tag가 존재하지 않거나, 속성이 존재하지 않는 등의 예외처리

 

< 소스 코드 >

#include <cmath>
#include <cstdio>
#include <vector>
#include <iostream>
#include <algorithm>
#include <stack>
#include <string>
using namespace std;

class tag
{
public:
	tag(){}
	tag(const string& tagname) : m_tagname(tagname) {}
	~tag(){}

public:
	vector<string> m_attribute;
	vector<string> m_value;
	vector<tag*> m_next;
	string m_tagname;
};

int main() 
{
	vector<tag*> heads;
	stack<tag*> tagStack;
	int n, q;
	cin >> n >> q;
	while (cin.get() != '\n');

	for (int i = 0; i < n; ++i)
	{
		string strInput = "";		
		getline(cin, strInput);

		if (strInput[1] == '/')
		{
			tagStack.pop();
			continue;
		}
		
		string tagname = "";
		// tag name
		int j;
		for (j = 1; strInput[j] != ' ' && strInput[j] != '>'; ++j)
			tagname += strInput[j];
		j++;
		// new tag
		tag* newTag = new tag(tagname);
		
		int flag = 0; // 0 : attribute / 1 : value
		while (j < strInput.size())
		{
			string tmp = "";
			// attribute
			if (!flag)
			{
				for (; strInput[j] != ' '; j++)
					tmp += strInput[j];
				newTag->m_attribute.push_back(tmp);
			}
				
			// value
			else
			{
				j = strInput.find('\"', j) + 1;
				for (; strInput[j] != '\"'; j++)
					tmp += strInput[j];
				newTag->m_value.push_back(tmp);
				j += 2;
			}
			flag = !flag;
		}

		// push
		if (tagStack.empty())
			heads.push_back(newTag);
		else
			tagStack.top()->m_next.push_back(newTag);
		tagStack.push(newTag);
	}

	for (int i = 0; i < q; ++i)
	{
		string strInput = "";
		getline(cin, strInput);
		tag* curTag = NULL;
		string tagName = "";

		int j = 0;
		while (j < strInput.size())
		{
			if (strInput[j] == '.' || strInput[j] == '~')
			{
				bool bFlag = false;
				// 최상위 태그 (heads)
				if (curTag == NULL)
				{
					for (int t = 0; t < heads.size(); ++t)
					{
						if (heads[t]->m_tagname == tagName)
						{
							curTag = heads[t];
							bFlag = true;
							break;
						}
					}
				}
				// 현재 가리키고 있는 태그에서 확인
				else
				{
					for (int t = 0; t < curTag->m_next.size(); ++t)
					{
						if (curTag->m_next[t]->m_tagname == tagName)
						{
							curTag = curTag->m_next[t];
							bFlag = true;
							break;
						}
					}
				}
				// 태그를 발견하지 못한 경우
				if (!bFlag)
				{
					cout << "Not Found!\n";
					break;
				}

				// 태그 name 초기화
				tagName = "";

				// ~가 나온 경우
				if (strInput[j] == '~')
				{
					j++;
					// 속성 이름 받아오기
					string st = strInput.substr(j, strInput.size() - j);
					string result = "";
					// 속성 이름이 존재할 경우 속성에 해당하는 값 받아오기
					for (int t = 0; t < curTag->m_attribute.size(); ++t)
					{
						if (st == curTag->m_attribute[t])
						{
							result = curTag->m_value[t];
							break;
						}
					}
					if (result == "")
						cout << "Not Found!\n";
					else
						cout << result << '\n';

					break;
				}
			}
			// 태그 이름 저장
			else
				tagName += strInput[j];
			j++;
		}
	}

	return 0;
}

'알고리즘 > HackerRank' 카테고리의 다른 글

[HackerRank] Tree : Top View  (0) 2019.06.15
[HackerRank] Array Manipulation  (0) 2019.06.10
[ HackerRank] Attending Workshops  (0) 2019.06.01
[HackerRank] Deque-STL  (0) 2019.06.01
[HackerRank] Bit Array  (1) 2019.05.31