web-dev-qa-db-fra.com

Python - Comment diviser une chaîne en caractères non alpha

J'essaie d'utiliser python pour analyser des lignes de code source c ++. La seule chose qui m'intéresse est d'inclure des directives.

    #include "header.hpp"

Je veux qu'il soit flexible et fonctionne toujours avec des styles de codage médiocres comme:

          #   include"header.hpp"  

J'en suis arrivé au point où je peux lire les lignes et couper les espaces avant et après le #. Cependant, j'ai encore besoin de savoir de quelle directive il s'agit en lisant la chaîne jusqu'à ce qu'un caractère non alpha soit rencontré, quelle que soit la météo, qu'il s'agisse d'un espace, d'une citation, d'une tabulation ou d'une parenthèse angulaire.

Donc, fondamentalement, ma question est: comment puis-je diviser une chaîne commençant par alphas jusqu'à ce qu'un non alpha soit rencontré?

Je pense que je pourrais être en mesure de le faire avec regex, mais je n'ai rien trouvé dans la documentation qui ressemble à ce que je veux.

Aussi, si quelqu'un a des conseils sur la façon dont j'obtiendrais le nom du fichier entre guillemets ou crochets, ce serait un plus.

11
nickeb96

Vous pouvez le faire avec une expression régulière. Cependant, vous pouvez également utiliser une simple boucle while.

def splitnonalpha(s):
   pos = 1
   while pos < len(s) and s[pos].isalpha():
      pos+=1
   return (s[:pos], s[pos:])

Tester:

>>> splitnonalpha('#include"blah.hpp"')
('#include', '"blah.hpp"')
7
kfx

Votre instinct pour utiliser l'expression régulière est correct.

import re
re.split('[^a-zA-Z]', string_to_split)

Le [^a-zA-Z] partie signifie "caractères non alphabétiques".

23
nlloyd

Les deux options mentionnées par d'autres qui sont les meilleures à mon avis sont re.split et re.findall:

>>> import re
>>> re.split(r'\W+', '#include "header.hpp"')
['', 'include', 'header', 'hpp', '']
>>> re.findall(r'\w+', '#include "header.hpp"')
['include', 'header', 'hpp']

Une référence rapide:

>>> setup = "import re; Word_pattern = re.compile(r'\w+'); sep_pattern = re.compile(r'\W+')"
>>> iterations = 10**6
>>> timeit.timeit("re.findall(r'\w+', '#header foo bar!')", setup=setup, number=iterations)
3.000092029571533
>>> timeit.timeit("Word_pattern.findall('#header foo bar!')", setup=setup, number=iterations)
1.5247418880462646
>>> timeit.timeit("re.split(r'\W+', '#header foo bar!')", setup=setup, number=iterations)
3.786440134048462
>>> timeit.timeit("sep_pattern.split('#header foo bar!')", setup=setup, number=iterations)
2.256173849105835

La différence fonctionnelle est que re.split conserve les jetons vides. Cela n'est généralement pas utile à des fins de tokenisation, mais les éléments suivants doivent être identiques à re.findall Solution:

>>> filter(bool, re.split(r'\W+', '#include "header.hpp"'))
['include', 'header', 'hpp']
5
Denis Drescher

Vous pouvez utiliser l'expression régulière. Le \W le jeton correspondra à tous les caractères non Word (ce qui est à peu près le même que non alphanumérique). Les caractères des mots sont A-Z, a-z, 0-9, et _. Si vous souhaitez également faire correspondre les traits de soulignement, vous pouvez simplement faire [\W_].

>>> import re
>>> line = '#   include"header.hpp"  ' 
>>> m = re.match(r'^\s*#\s*include\W+([\w\.]+)\W*$', line)
>>> m.group(1)
'header.hpp'
2
Patrick Carroll
import re
s = 'foo bar- blah/hm.lala'
print(re.findall(r"\w+",s))

sortie: ['foo', 'bar', 'blah', 'hm', 'lala']

1
Daniyal Syed

Bien qu'elles ne soient pas exactes, la plupart des directives d'en-tête d'analyse comme celle-ci

(?m)^\h*#\h*include\h*["<](\w[\w.]*)\h*[">]

Où, (? M) est en mode multiligne,\h est un espace horizontal (alias [^\S\r\n]).

0
user557597

Cela marche:

import re

test_str = '    #   include "header.hpp"'

match = re.match(r'\s*#\s*include\s*("[\w.]*")', test_str)
if match:
    print match.group(1)
0
Garrett R