2009-01-15 8 views
14

J'écris un programme qui analyse du texte avec une expression régulière. L'expression régulière doit être obtenue auprès de l'utilisateur. Je déside à utiliser la syntaxe glob pour l'entrée de l'utilisateur, et convertir la chaîne glob à l'expression régulière en interne. Par exemple:Créer une regex à partir de l'expression globale

"foo.? bar*" 

doivent être converties en

"^.*foo\.\w\bar\w+.*" 

D'une certaine façon, j'ai besoin d'échapper à tous les personnages significatifs de la chaîne, alors je dois remplacer glob * et? caractères avec une syntaxe regexp appropriée. Quel est le moyen le plus pratique de le faire?

+0

Le regex semble un peu étrange. Comme: "^. * Foo" pourrait être écrit comme "foo". Et je pense que l'étoile de globbing se traduit par la regex ". *?". Où est passé l'espace dans la recherche? Et \ bar correspond à des mots commençant par "ar". – PEZ

Répondre

-2
+15

Juste poster un lien comme une réponse n'est pas une bonne réponse. Que faire si le lien se brise à l'avenir? Vous êtes encouragé à citer le lien dans votre réponse, de sorte que si le lien se brise, la réponse existe toujours sur Stack Overflow. –

1

écrire ma propre fonction, en utilisant C++ et boost :: regex

std::string glob_to_regex(std::string val) 
{ 
    boost::trim(val); 
    const char* expression = "(\\*)|(\\?)|([[:blank:]])|(\\.|\\+|\\^|\\$|\\[|\\]|\\(|\\)|\\{|\\}|\\\\)"; 
    const char* format = "(?1\\\\w+)(?2\\.)(?3\\\\s*)(?4\\\\$&)"; 
    std::stringstream final; 
    final << "^.*"; 
    std::ostream_iterator<char, char> oi(final); 
    boost::regex re; 
    re.assign(expression); 
    boost::regex_replace(oi, val.begin(), val.end(), re, format, boost::match_default | boost::format_all); 
    final << ".*" << std::ends; 
    return final.str(); 
} 

il ressemble à tout fonctionne très bien

2

Je ne suis pas sûr entièrement comprendre les exigences. Si je suppose que les utilisateurs veulent trouver des "entrées" de texte où leur recherche correspond alors je pense que cette manière brute fonctionnerait comme un début. D'abord échapper tout regex-significatif. Utilisez ensuite des remplacements non-regex pour remplacer les caractères glob (maintenant échappés) et construisez l'expression régulière. Comme tant en Python:

regexp = re.escape(search_string).replace(r'\?', '.').replace(r'\*', '.*?') 

Pour la chaîne de recherche dans la question, il construit une expression rationnelle qui ressemble si (brut):

foo\..\ bar.*? 

Utilisé dans un extrait de Python:

search = "foo.? bar*" 
text1 = 'foo bar' 
text2 = 'gazonk foo.c bar.m m.bar' 

searcher = re.compile(re.escape(s).replace(r'\?', '.').replace(r'\*', '.*?')) 

for text in (text1, text2): 
    if searcher.search(text): 
    print 'Match: "%s"' % text 

Produit:

Match: "gazonk foo.c bar.m m.bar" 

Notez que si vous examinez l'objet de correspondance, vous pouvez en savoir plus sur la correspondance et l'utiliser pour la mise en évidence ou autre.

Bien sûr, il pourrait y avoir plus, mais cela devrait être un début.

+0

C'est bon, mais vous avez besoin de remplacer() | \ [] et d'autres caractères significatifs dans la chaîne du serar – Lazin

+0

Merci de l'avoir signalé. Maintenant corrigé. – PEZ

43

pas besoin de hacks incomplètes ou non fiables. il y a une fonction incluse avec python pour cette

>>> import fnmatch 
>>> fnmatch.translate('*.foo') 
'.*\\.foo$' 
>>> fnmatch.translate('[a-z]*.txt') 
'[a-z].*\\.txt$' 
1

fonction de RegExp.fromWildExp de jPaq fait quelque chose semblable à cela. Ce qui suit est tirée de l'exemple qui se trouve sur la page d'accueil du site:

// Find a first substring that starts with a capital "C" and ends with a 
// lower case "n". 
alert("Where in the world is Carmen Sandiego?".findPattern("C*n")); 

// Finds two words (first name and last name), flips their order, and places 
// a comma between them. 
alert("Christopher West".replacePattern("(<*>) (<*>)", "p", "$2, $1")); 

// Finds the first number that is at least three numbers long. 
alert("2 to the 64th is 18446744073709551616.".findPattern("#{3,}", "ol")); 
Questions connexes