2
votes

Remplacement d'un modèle d'identifiant spécial par re.sub en python

Je suis nouveau dans les regex et j'ai un remplacement de regex dans un re.sub que je ne peux pas comprendre.

1-Some String 
2-Some String 
3-Some String  
4-Some String (Fubar )
5-Some String (Fubar - .67 A)
6-Some String  
7-Some String
8-Some  String

Le code devrait s'afficher:

1-Some String
2-Some String
3-Some String
4-Some String (Fubar)
5-Some String (Fubar)
6-Some String
7-Some String   
8-Some #1 String   

Mais, à la place, je reçois actuellement ceci (avec 4,5,8 pas entièrement convertis):

import re

test_cases = [
    "1-Some String #0123",
    "2-Some String #1234-56-a",
    "3-Some String #1234-56A ",
    "4-Some String (Fubar/ #12-345-67A)",
    "5-Some String (Fubar - #12-345.67 A)",
    "6-Some String / #123",
    "7-Some String/#0233",
    "8-Some #1 String/#0233"
    ]

for test in test_cases:
    test = re.sub(r'[/|#][A-Z|a-z|0-9|-]*','', test)
    print(test)


1 commentaires

Vous n'avez pas inclus d'espaces ou de points dans votre expression régulière afin qu'ils ne correspondent pas


4 Réponses :


0
votes

Je ne pouvais pas les intégrer dans une seule expression régulière, peut-être que quelqu'un le pourra. Voici une solution sur 2 lignes:

1-Some String
2-Some String
3-Some String
4-Some String (Fubar)
5-Some String (Fubar)
6-Some String
7-Some String
8-Some

Résultat:

import re

test_cases = [
    "1-Some String #0123",
    "2-Some String #1234-56-a",
    "3-Some String #1234-56A ",
    "4-Some String (Fubar/ #12-345-67A)",
    "5-Some String (Fubar - #12-345.67 A)",
    "6-Some String / #123",
    "7-Some String/#0233",
    "8-Some #1 String/#0233"
    ]

for test in test_cases:
    test = re.sub(r'[\/#][\w\s\d\-]*', '', test)
    test = re.sub(r'[\s\.\-\d]+\w+\)', ')', test)
    print(test)

Expliquez:

  1. \ w pour a-zA-Z
  2. \ d pour 0-9
  3. \ s pour les espaces
  4. \. pour le point
  5. \ - pour moins

Mais je suis confus avec votre dernière ligne de sortie, pourquoi elle produit # 1 String , en fonction de quoi? Si vous confirmez que vous pouvez écrire une expression régulière spécifique pour ce modèle.


1 commentaires

Il vous manque des parties dans la ligne 8: p :) On dirait que le motif à 1 ligne de @tshiono fonctionne



3
votes

Veuillez essayer ce qui suit:

1-Some String
2-Some String
3-Some String
4-Some String (Fubar)
5-Some String (Fubar)
6-Some String
7-Some String
8-Some #1 String

Résultat:

import re

test_cases = [
    "1-Some String #0123",
    "2-Some String #1234-56-a",
    "3-Some String #1234-56A ",
    "4-Some String (Fubar/ #12-345-67A)",
    "5-Some String (Fubar - #12-345.67 A)",
    "6-Some String / #123",
    "7-Some String/#0233",
    "8-Some #1 String/#0233"
    ]

for test in test_cases:
    test = re.sub(r'\s*([/#]|- )[\sA-Za-z0-9-#\.]*(?=(\)|$))','', test)
    print(test)

L'expression régulière (sous-chaîne à supprimer) peut être définie comme: p>

  • Pour commencer par "/", "#" ou "-"
  • Peut être précédé d'espaces blancs
  • Se composer d'espaces blancs, de caractères alphanumériques, de traits d'union, de hachages ou de points
  • À ancrer par "fin de ligne" ou ")" en utilisant une anticipation positive

Alors l'expression régulière ressemblera à: \ s * ([/ #] | -) [\ sA-Za-z0-9 - # \.] * (? = (\) | $))

anticipation positive peut nécessiter des explications. Le modèle (? = Regex) est une assertion de largeur nulle signifiant suivi de regex . L'avantage est que la sous-chaîne correspondante n'inclut pas le regex et vous pouvez l'utiliser comme ancre.


3 commentaires

pourrait bien vouloir fournir une explication de votre modèle. Tx.


@SanV J'ai mis à jour ma réponse avec quelques explications. J'espère que cela aide.


Merci d'avoir fourni cette solution .... J'ai comparé celle-ci à celle fournie par «Le quatrième oiseau». Donc, en gros, comparer '\ s * ([/ #] | -) [\ sA-Za-z0-9 - # \.] * (? = () | $))' À '\ s * ([/ #] | -) [\ sA-Za-z0-9 - # \.] * (? = () | $)) 'car j'étais curieux de connaître les performances. Il est apparu que ce dernier est un peu plus rapide (environ 10%). Je ne sais pas pourquoi.



1
votes

Il est probablement plus facile de le faire en deux étapes:

Premièrement: nettoyez la pièce entre parenthèses. Après le '(' et quelques lettres, supprimez tout jusqu'à la fermeture ')'.

Deuxièmement: supprimez les éléments indésirables à la fin d'une ligne. Une ligne se termine par «#» suivi de 2 chiffres ou plus ou d'un «/». Il peut y avoir un espace avant le "#" ou "/".

import re

paren_re = re.compile(r"([(][a-zA-Z]+)([^)]*)")

eol_re = re.compile(r"(.*?)\s*(?:#\d\d|/).*")

for line in test_cases:
    result = paren_re.sub(r"\1", line)
    result = eol_re.sub(r"\1", result)

    print(result)


0 commentaires

2
votes

Une autre option consiste à ne faire correspondre que la dernière occurrence de # en utilisant une anticipation négative (?! [^ # \ n \ r] * #) . Pour plus de clarté, j'ai mis un espace [] correspondant entre crochets.

[ ]*(?:[/-][ ]*)?#(?![^#\n\r]*#)[\da-zA-Z. -]+

Explication

  • [] * Correspond à 0 fois ou plus un espace
  • (?: [/ -] [] *)? Faire correspondre éventuellement / ou - et 0+ espaces
  • # Correspondre littéralement
  • (?! [^ # \ n \ r] * #) Lookahead négatif, affirmer quand est om le droit ne contient pas #
  • [\ da-zA-Z. -] + Correspond à 1+ fois ce qui est répertorié dans la classe de caractères

Démo Regex

Dans l'utilisation de remplacement une chaîne vide.


0 commentaires