Skip to content

Instantly share code, notes, and snippets.

@vlaleli
Created December 1, 2025 12:08
Show Gist options
  • Select an option

  • Save vlaleli/2551095894506b698c5b449ee75cb6ac to your computer and use it in GitHub Desktop.

Select an option

Save vlaleli/2551095894506b698c5b449ee75cb6ac to your computer and use it in GitHub Desktop.
#include "HtmlValidator.h"
#include <fstream>
#include <stack>
#include <string>
#include <cctype>
using namespace std;
bool HtmlValidator::validateFile(const string& path, string& errorMessage) {
ifstream in(path);
if (!in) {
errorMessage = "Не вдалося відкрити файл.";
return false;
}
string content((istreambuf_iterator<char>(in)), istreambuf_iterator<char>());
in.close();
return validateContent(content, errorMessage);
}
bool HtmlValidator::validateContent(const string& content, string& errorMessage) {
stack<string> tags;
size_t i = 0;
size_t n = content.size();
while (i < n) {
if (content[i] == '<') {
size_t pos = content.find('>', i + 1);
if (pos == string::npos) {
errorMessage = "Знак '<' без відповідного '>'.";
return false;
}
string inside = content.substr(i + 1, pos - i - 1);
size_t start = 0;
while (start < inside.size() &&
isspace((unsigned char)inside[start])) {
++start;
}
size_t end = inside.size();
while (end > start &&
isspace((unsigned char)inside[end - 1])) {
--end;
}
if (start >= end) {
errorMessage = "Порожній тег.";
return false;
}
inside = inside.substr(start, end - start);
if (inside.rfind("!--", 0) == 0) {
size_t close = content.find("-->", i + 4);
if (close == string::npos) {
errorMessage = "Незакритий коментар.";
return false;
}
i = close + 3;
continue;
}
if (inside[0] == '!' || inside[0] == '?') {
i = pos + 1;
continue;
}
bool isClosing = inside[0] == '/';
bool selfClosing = inside.back() == '/';
size_t nameStart = isClosing ? 1 : 0;
while (nameStart < inside.size() &&
isspace((unsigned char)inside[nameStart])) {
++nameStart;
}
size_t nameEnd = nameStart;
while (nameEnd < inside.size() &&
!isspace((unsigned char)inside[nameEnd]) &&
inside[nameEnd] != '/') {
++nameEnd;
}
if (nameStart >= nameEnd) {
errorMessage = "Некоректний тег.";
return false;
}
string name = inside.substr(nameStart, nameEnd - nameStart);
if (!isClosing && !selfClosing) {
tags.push(name);
} else if (isClosing) {
if (tags.empty()) {
errorMessage = string("Зайвий закриваючий тег </") + name + ">.";
return false;
}
if (tags.top() != name) {
errorMessage = string("Очікувався </") + tags.top() + ">.";
return false;
}
tags.pop();
}
i = pos + 1;
} else {
++i;
}
}
if (!tags.empty()) {
errorMessage = string("Не всі теги закриті. Очікувався </") + tags.top() + ">.";
return false;
}
return true;
}
#ifndef HTMLVALIDATOR_H
#define HTMLVALIDATOR_H
#include <string>
class HtmlValidator {
public:
bool validateFile(const std::string& path, std::string& errorMessage);
private:
bool validateContent(const std::string& content, std::string& errorMessage);
};
#endif
#include <iostream>
#include <string>
#include "HtmlValidator.h"
using namespace std;
int main() {
string path;
cout << "Введіть шлях до HTML-файлу: ";
getline(cin, path);
HtmlValidator validator;
string error;
if (validator.validateFile(path, error)) {
cout << "Файл валідний за заданими правилами." << endl;
} else {
cout << "Файл НЕвалідний: " << error << endl;
}
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment