NOVINKA - Online rekvalifikační kurz Python programátor. Oblíbená a studenty ověřená rekvalifikace - nyní i online.
Hledáme nové posily do ITnetwork týmu. Podívej se na volné pozice a přidej se do nejagilnější firmy na trhu - Více informací.

Diskuze: Jak vytvořit regex pattern na kontrolu názvu souboru

V předchozím kvízu, Online test znalostí C++, jsme si ověřili nabyté zkušenosti z kurzu.

Jak se ti líbí článek?
Před uložením hodnocení, popiš prosím autorovi, co je špatněZnaků 0 z 50-500
Jak se ti kurz líbí?
Tvé hodnocení kurzuZnaků 0 z 50-500
Aktivity
Avatar
Michal Hadraba:15.6.2023 23:49

Nejsem schopen vytvořit pattern, který by zkontroloval, zda text lze použít jako název windows souboru.
Zajímavé třeba je že přepínač :alpha: nekaceptuje znaky s diakritikou zatímco přepínač /w akceptuje (kromě číslic) i diakritiku.

const std::wregex pattern(L"([:alpha:]*)");
const std::wregex pattern1(L"(\\w*)");
bool b = std::regex_match(L"šžŘŽÝ", pattern);
bool c = std::regex_match(L"šžŘŽÝ", pattern1);

b je false a c je true.

Zkusil jsem: Kopíroval jsem různé příklady na fórech, bohužel většinou pro jiné jazyky. Většinou to vedlo k neošetřené výjimce ve funkci void _Parser, v hlavičkové souboru regex.h

Chci docílit: Prověřit, zda název zadaný uživatelem je použitelný pro název windows souboru.

 
Odpovědět
15.6.2023 23:49
Avatar
DarkCoder
Člen
Avatar
Odpovídá na Michal Hadraba
DarkCoder:16.6.2023 0:26

Pro test, zda název lze použít jako název souboru pod Windows, můžeš jednoduše otevřít soubor pro zápis u kterého vyhodnotíš úspěšnost volání funkce fopen().

#include <stdio.h>
#include <stdbool.h>

bool isValidWindowsFilename(const char* filename) {
    FILE* file = fopen(filename, "w");
    if (file != NULL) {
        fclose(file);
        remove(filename);
        return true;
    }
    return false;
}

int main(void) {
    const char* filename = "test.txt";
    bool isValid = isValidWindowsFilename(filename);
    if (isValid) {
        printf("Název souboru je platný.\n");
    } else {
        printf("Název souboru není platný.\n");
    }
    return 0;
}

Žádný regex, čisté C.

Nahoru Odpovědět
16.6.2023 0:26
"I ta nejlepší poučka postrádá na významu, není-li patřičně předána." - DarkCoder
Avatar
Odpovídá na DarkCoder
Michal Hadraba:16.6.2023 6:22

To jo, ale jednak si myslím, že to bude o dost pomalejší, jednak já to pak potřebuji ještě upravit pro názvy komponent v Autocadu, která má podobná, leč trochu jiná pravidla. Takže bych se potřeboval držet toho regexu.

Editováno 16.6.2023 6:22
 
Nahoru Odpovědět
16.6.2023 6:22
Avatar
DarkCoder
Člen
Avatar
Odpovídá na Michal Hadraba
DarkCoder:16.6.2023 6:53

Pokud jde o jednoduchou validaci souborového jména, která využívá operace otevření a zavření souboru, bude tato validace pravděpodobně rychlejší nežli varianta za použití regulárnich výrazů.

Dále funkce fopen je přímo napojena na souborový systém. Poměrně rychlé otevření a zavření souboru pomocí fopen a fclose je často efektivním způsobem pro jednoduchou validaci souborových jmen. Regulární výrazy jsou užitečné v případech, kdy je třeba provádět složitější kontrolu nebo vyhledávání ve vzorcích v řetězci.

Pokud se chceš i nadále držet regulárnich výrazů, pak můžeš zkusit toto:

#include <iostream>
#include <regex>

bool isValidWindowsFilename(const std::string& filename) {
    std::regex pattern("[a-zA-Z0-9_]+\\.txt");
    return std::regex_match(filename, pattern);
}

int main() {
    std::string filename = "test.txt";
    bool isValid = isValidWindowsFilename(filename);
    if (isValid) {
        std::cout << "Název souboru je platný." << std::endl;
    } else {
        std::cout << "Název souboru není platný." << std::endl;
    }
    return 0;
}

Zde je použit regulární výraz [a-zA-Z0-9_]+\\.txt, který odpovídá souborovým jménům, která obsahují pouze písmena (velká i malá), číslice a podtržítka a končí na ".txt". Můžeš pak přizpůsobit tento výraz podle konkrétních pravidel Autocadu.

Nahoru Odpovědět
16.6.2023 6:53
"I ta nejlepší poučka postrádá na významu, není-li patřičně předána." - DarkCoder
Avatar
Odpovídá na DarkCoder
Michal Hadraba:16.6.2023 7:06

A třeba aby to umelo i háčky. Tak to bude

...("[//w_#$- []()]+\\.txt")

A to mi moc nefunguje

 
Nahoru Odpovědět
16.6.2023 7:06
Avatar
DarkCoder
Člen
Avatar
Odpovídá na Michal Hadraba
DarkCoder:16.6.2023 7:25

Pak zkus:

bool isValidWindowsFilename(const std::string& filename) {
    std::regex pattern(R"([\p{L}0-9_\#$\[\]\(\)\s-]+\.txt)", std::regex::icase | std::regex::extended);
    return std::regex_match(filename, pattern);
}

Zde je použit rozšířený regulární výraz s Unicode kategorií [\p{L}], která odpovídá libovolnému písmenu včetně písmen s diakritikou. Použitím [\p{L}0-9_\#$\[\]\(\)\s-]+ se zajistí, že se mohou vyskytnout i další povolené znaky, které si uvedl (#$- []()), a také čísla, podtržítka a mezery.

Regulární výraz je zapsán s použitím raw string literalu (R"(...)"), což umožňuje psát vzorce bez nutnosti escapovat zpětnými lomítky.

Přepínače std::regex::icase zajišťuje, že na rozlišování velkých a malých písmen se nehledí, a std::regex::ex­tended umožňuje použití rozšířené syntaxe regulárních výrazů.

Akceptované řešení
+20 Zkušeností
+2,50 Kč
Řešení problému
Nahoru Odpovědět
16.6.2023 7:25
"I ta nejlepší poučka postrádá na významu, není-li patřičně předána." - DarkCoder
Avatar
Odpovídá na DarkCoder
Michal Hadraba:16.6.2023 8:32

Tak bohužel, z nějakého důvodu to furt hází unhadled exception ve funkci void _Parser, v hlavičkovém souboru regex.h. Při vytváření toho pattternu (2. řádek)

std::string filename = "asdkjhkjřžěáíýQĚÍČÁŘÝĚKJDHAFKJ0101*&&_)(";
std::regex pattern(R"([\p{L}0-9_\#$\[\]\(\)\s-]+\.txt)", std::regex::icase | std::regex::extended);
bool bb = std::regex_match(filename, pattern);
 
Nahoru Odpovědět
16.6.2023 8:32
Avatar
Odpovídá na Michal Hadraba
Michal Hadraba:16.6.2023 8:44

A když jsem to takto zjednodušil

std::string filename = "asdkjhkjKJDHAFK";
std::regex pattern(R"([\p{L}]+)", std::regex::icase | std::regex::extended);
bool bb = std::regex_match(filename, pattern);

tak to sice přestalo padat, ale zase to nefunguje, je to stále false....
(požívám VS 2019 + C++14)

Editováno 16.6.2023 8:44
 
Nahoru Odpovědět
16.6.2023 8:44
Avatar
DarkCoder
Člen
Avatar
Odpovídá na Michal Hadraba
DarkCoder:16.6.2023 9:16

Příčinou může být nepodporovaná syntaxe regulárního výrazu pro verzi C++ a překladače.

V rámci C++14 s použitím knihovny <regex> jsou k dispozici omezené možnosti pro Unicode kategorie. Místo \p{L} zkus použít [[:alpha:]], což odpovídá alfanumerickým znakům (písmena) bez ohledu na velikost písmen.

bool isValidWindowsFilename(const std::string& filename) {
    std::regex pattern(R"([[:alpha:]]+)", std::regex::icase);
    return std::regex_match(filename, pattern);
}
Nahoru Odpovědět
16.6.2023 9:16
"I ta nejlepší poučka postrádá na významu, není-li patřičně předána." - DarkCoder
Děláme co je v našich silách, aby byly zdejší diskuze co nejkvalitnější. Proto do nich také mohou přispívat pouze registrovaní členové. Pro zapojení do diskuze se přihlas. Pokud ještě nemáš účet, zaregistruj se, je to zdarma.

Zobrazeno 9 zpráv z 9.