1
votes

comment extraire l'année de différents types de date en python

J'ai une colonne avec différents types de date tels que:

def get_date(date):
        number= re.findall('\[0-9]\-{0,1}\\{0,1}\/{0,1}\[0-9]\-{0,1}\\{0,1}\/{0,1}\[0-9]', date)
        return number[6:]

Je ne veux que l'année.

J'ai essayé différents types de regex tels que:

2\06\1998
21.11.1998  
18-02-2001
03/05/1999 
20 july 1999

mais je ne peux pas extraire l'année. quelle est la regex la plus appropriée pour ce cas? ce n'est pas un problème de faire deux types d'expressions régulières, une pour le format jj / mm / aaaa et une pour la date avec le mois en lettre.


7 commentaires

col.str [-4:] ?


Essayez de trouver une pièce avec un numéro à 4 chiffres comme: re.findall (r '\ d {4}', date)


df.col_name.str [-4:]


@MarkWang Entre le '2019/08/27'


@Anup Voir ci-dessus


re.split (r '\\ | \. | - | \ / |', date) [- 1] ?


En supposant que l'année soit toujours à la fin, / (\ d {4}) (?: \ S +)? $ / Gm fonctionnerait.


4 Réponses :


0
votes

Vous pouvez utiliser 2 groupes de capture, où dans le premier groupe vous capturez le diviseur pour faire correspondre un diviseur cohérent pour le second en utilisant une référence arrière \ 1 .

L'année partie est capturée dans le second groupe.

(?<!\S)\d+([\\/. -])(?:\d+|[a-z]+)\1(\d{4})(?!\S)

Regex démo

Au lieu d'utiliser les ancres ^ et $ , vous pouvez également utiliser Lookarounds

^\d+([\\/. -])(?:\d+|[a-z]+)\1(\d{4})$

Démo Regex

Parties du motif

  • (? Affirmer que ce qui se trouve à gauche n'est pas un caractère sans espace
  • \ d + Faire correspondre 1+ chiffres
  • ([\\ /. -]) Groupe de capture 1, correspond à l'un des éléments répertoriés
  • (?: Groupe sans capture
    • \ d + Faire correspondre 1+ chiffres
    • | ou
    • [a-z] + Correspondre à 1+ caractères minuscules
  • ) Fermer le groupe non caputring
  • \ 1 Retour sur ce qui est capturé dans le groupe 1
  • (\ d {4}) Groupe de capture 2, correspond à 4 chiffres pour l'année
  • (?! \ S) Affirmez que ce qui se trouve à droite n'est pas un caractère sans espace


0 commentaires

0
votes

J'utiliserais une simple \ d {4} regex .

import re

s = """2\\06\\1998
21.11.1998  
18-02-2001
03/05/1999 
20 july 1999"""
for date in s.splitlines():
    year = re.search(r"\d{4}", date).group(0)
    print(year)


0 commentaires

0
votes

Pandas to_datetime est étonnamment bon à reconnaître différents formats de date. Le seul problème que cela aura est avec les barres obliques inverses, mais si vous pouvez les remplacer en utilisant un formatage de chaîne, je pense que c'est plus facile que d'utiliser une expression régulière.

import pandas as pd
df = pd.DataFrame({"date": ["2\\06\\1998", "21.11.1998", "18-02-2001", "03/05/1999", "20 july 1999"]})

df["date"] = df["date"].str.replace("\\", "/")
df["date"] = pd.to_datetime(df["date"])
df["date"].dt.year

0    1998
1    1998
2    2001
3    1999
4    1999
Name: date, dtype: int64


0 commentaires

2
votes

Ne tombez pas dans le regex / «déshabiller les 4 derniers personnages». Si une date dans un autre format arrive (par exemple 2019-08-27 ), toute solution d'expression régulière / de décapage naïve sera interrompue.

Utilisez pd.to_datetime pour laisser les pandas s'occuper avec l'analyse, puis saisissez simplement dt.year.

0    1998
1    1998
2    2001
3    1999
4    1999
5    2019

Outputs

df = pd.DataFrame({'a': ['2/06/1998', '21.11.1998', '18-02-2001', '03/05/1999',
                         '20 july 1999', '2019-08-27']})
df['a'] = pd.to_datetime(df['a'])
print(df['a'].dt.year)

Remarque : Notez que j'ai dû changer la direction des barres obliques ( 2 \ 06 \ 1998 à 2/06/1998 ) mais c'est un tout petit prix à payer pour obtenir un solution bien plus robuste en retour.


10 commentaires

La solution regex qui extrait le nombre à 4 chiffres fonctionnera sur des formats de date à 99% (pas de date / heure)


@OlvinRoght Ma solution fonctionnera à 100% (tant que le format est standard et pas complètement arbitraire) et avec beaucoup moins de code "non testé"


C'est pourquoi vous avez modifié les données source de l'article pour le laisser "fonctionner à 100%"? : D: D: D


@OlvinRoght ouais, comparons une solution qui vous oblige à appeler str.replace pour changer la direction des barres obliques mais prend en charge TOUS les formats de date et de date / heure standard , à une solution qui est en utilisant une expression régulière qui cassera si elle obtient un format inattendu (même si c'est standard)


Pourriez-vous me fournir un format de date où l'expression régulière \ d {4} se cassera et pas les pandas?


@OlvinRoght 2019-08-27 1000


J'ai remarqué deux fois que ce devrait être le format de la date. Et de toute façon, cette regex capturera la première occurrence qui est l'année.


@OlvinRoght Today OP ne traite que des dates, demain OP devra traiter datetime ... Ma solution leur sauve une autre question :)


merci @DeepSpace. cela me semble la meilleure solution. J'ai une autre question. pourquoi dans ma sortie l'année est de type flottant? 1998.0 par exemple.


@IvanMera Pas sûr, mais vous pouvez utiliser .dt.year.astype (int) ou tout autre type équivalent np