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.
4 Réponses :
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)
Au lieu d'utiliser les ancres ^ et $ , vous pouvez également utiliser Lookarounds
^\d+([\\/. -])(?:\d+|[a-z]+)\1(\d{4})$
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 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)
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
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.
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
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 +)? $ / Gmfonctionnerait.