Convertir DataSring Internacional a ISO-Format -- python campo con datetime campo con i18n camp codereview Relacionados El problema

Convert international datestring to ISO-format


3
vote

problema

Español

La siguiente función toma un DataString en el formulario D-MMM-YYYY y lo convierte en el formato de fecha ISO (YYAY-MM-DD). Los delimitadores pueden ser guiones, espacio o asyncTimer7 , y se pueden usar abreviaturas holandesas o en inglés.

Ahora, sé que hay asyncTimer8 , pero devuelve asyncTimer9 Si intenta analizar algo con un mes que no es inglés. No he digerido toda su documentación, pero creo que 99887766555443320 está diseñado principalmente para el cálculo de la fecha. No lo estoy haciendo, solo estoy limpiando la entrada de usuario.

Así que escribí mi propia.

  Option Explicit  Implements ITicker 'to allow tick method to remain hidden  Public Event Tick() Public Event Timeout() Public Event Complete()  Private Const waitIndefinitely As Double = -1  Private Type tTimer     tickFrequency As Double                      'in seconds     startTime As Double     endTime As Double     neverTimeout As Boolean     conditionAddress As LongPtr End Type  Private this As tTimer  Public Sub Await(ByRef processComplete As Boolean, Optional ByVal tickFrequency As Double = 0.5, Optional ByVal maxWait As Double = 10)     this.conditionAddress = VarPtr(processComplete)     If maxWait = waitIndefinitely Then         this.neverTimeout = True     ElseIf maxWait >= 0 Then         this.startTime = timer         this.endTime = this.startTime + maxWait     Else         Err.Raise 5, , "Max wait must be positive or -1 (for no timeout)"     End If      startTicking tickFrequency, Me End Sub  Private Sub ITicker_Tick()     If Peek(this.conditionAddress, vbBoolean) Then 'check if val has changed         stopTicking         RaiseEvent Complete     ElseIf timer > this.endTime Then         stopTicking         RaiseEvent Timeout     Else         RaiseEvent Tick     End If End Sub  Private Sub Class_Terminate()     stopTicking End Sub 1  

El mes y el año de REGEX MATCH Parses pueden no ser bonitos, pero funciona y es fácil expandirse para otros patrones. Del mismo modo, para el número de la búsqueda del número con Option Explicit Implements ITicker 'to allow tick method to remain hidden Public Event Tick() Public Event Timeout() Public Event Complete() Private Const waitIndefinitely As Double = -1 Private Type tTimer tickFrequency As Double 'in seconds startTime As Double endTime As Double neverTimeout As Boolean conditionAddress As LongPtr End Type Private this As tTimer Public Sub Await(ByRef processComplete As Boolean, Optional ByVal tickFrequency As Double = 0.5, Optional ByVal maxWait As Double = 10) this.conditionAddress = VarPtr(processComplete) If maxWait = waitIndefinitely Then this.neverTimeout = True ElseIf maxWait >= 0 Then this.startTime = timer this.endTime = this.startTime + maxWait Else Err.Raise 5, , "Max wait must be positive or -1 (for no timeout)" End If startTicking tickFrequency, Me End Sub Private Sub ITicker_Tick() If Peek(this.conditionAddress, vbBoolean) Then 'check if val has changed stopTicking RaiseEvent Complete ElseIf timer > this.endTime Then stopTicking RaiseEvent Timeout Else RaiseEvent Tick End If End Sub Private Sub Class_Terminate() stopTicking End Sub 2 , que es más conciso que una cadena de Option Explicit Implements ITicker 'to allow tick method to remain hidden Public Event Tick() Public Event Timeout() Public Event Complete() Private Const waitIndefinitely As Double = -1 Private Type tTimer tickFrequency As Double 'in seconds startTime As Double endTime As Double neverTimeout As Boolean conditionAddress As LongPtr End Type Private this As tTimer Public Sub Await(ByRef processComplete As Boolean, Optional ByVal tickFrequency As Double = 0.5, Optional ByVal maxWait As Double = 10) this.conditionAddress = VarPtr(processComplete) If maxWait = waitIndefinitely Then this.neverTimeout = True ElseIf maxWait >= 0 Then this.startTime = timer this.endTime = this.startTime + maxWait Else Err.Raise 5, , "Max wait must be positive or -1 (for no timeout)" End If startTicking tickFrequency, Me End Sub Private Sub ITicker_Tick() If Peek(this.conditionAddress, vbBoolean) Then 'check if val has changed stopTicking RaiseEvent Complete ElseIf timer > this.endTime Then stopTicking RaiseEvent Timeout Else RaiseEvent Tick End If End Sub Private Sub Class_Terminate() stopTicking End Sub 3 para que coincida con las cadenas de mes en números.

En lugar del código entre Option Explicit Implements ITicker 'to allow tick method to remain hidden Public Event Tick() Public Event Timeout() Public Event Complete() Private Const waitIndefinitely As Double = -1 Private Type tTimer tickFrequency As Double 'in seconds startTime As Double endTime As Double neverTimeout As Boolean conditionAddress As LongPtr End Type Private this As tTimer Public Sub Await(ByRef processComplete As Boolean, Optional ByVal tickFrequency As Double = 0.5, Optional ByVal maxWait As Double = 10) this.conditionAddress = VarPtr(processComplete) If maxWait = waitIndefinitely Then this.neverTimeout = True ElseIf maxWait >= 0 Then this.startTime = timer this.endTime = this.startTime + maxWait Else Err.Raise 5, , "Max wait must be positive or -1 (for no timeout)" End If startTicking tickFrequency, Me End Sub Private Sub ITicker_Tick() If Peek(this.conditionAddress, vbBoolean) Then 'check if val has changed stopTicking RaiseEvent Complete ElseIf timer > this.endTime Then stopTicking RaiseEvent Timeout Else RaiseEvent Tick End If End Sub Private Sub Class_Terminate() stopTicking End Sub 4 y Option Explicit Implements ITicker 'to allow tick method to remain hidden Public Event Tick() Public Event Timeout() Public Event Complete() Private Const waitIndefinitely As Double = -1 Private Type tTimer tickFrequency As Double 'in seconds startTime As Double endTime As Double neverTimeout As Boolean conditionAddress As LongPtr End Type Private this As tTimer Public Sub Await(ByRef processComplete As Boolean, Optional ByVal tickFrequency As Double = 0.5, Optional ByVal maxWait As Double = 10) this.conditionAddress = VarPtr(processComplete) If maxWait = waitIndefinitely Then this.neverTimeout = True ElseIf maxWait >= 0 Then this.startTime = timer this.endTime = this.startTime + maxWait Else Err.Raise 5, , "Max wait must be positive or -1 (for no timeout)" End If startTicking tickFrequency, Me End Sub Private Sub ITicker_Tick() If Peek(this.conditionAddress, vbBoolean) Then 'check if val has changed stopTicking RaiseEvent Complete ElseIf timer > this.endTime Then stopTicking RaiseEvent Timeout Else RaiseEvent Tick End If End Sub Private Sub Class_Terminate() stopTicking End Sub 5 , también tuve esto, que usa DateTime:

  Option Explicit  Implements ITicker 'to allow tick method to remain hidden  Public Event Tick() Public Event Timeout() Public Event Complete()  Private Const waitIndefinitely As Double = -1  Private Type tTimer     tickFrequency As Double                      'in seconds     startTime As Double     endTime As Double     neverTimeout As Boolean     conditionAddress As LongPtr End Type  Private this As tTimer  Public Sub Await(ByRef processComplete As Boolean, Optional ByVal tickFrequency As Double = 0.5, Optional ByVal maxWait As Double = 10)     this.conditionAddress = VarPtr(processComplete)     If maxWait = waitIndefinitely Then         this.neverTimeout = True     ElseIf maxWait >= 0 Then         this.startTime = timer         this.endTime = this.startTime + maxWait     Else         Err.Raise 5, , "Max wait must be positive or -1 (for no timeout)"     End If      startTicking tickFrequency, Me End Sub  Private Sub ITicker_Tick()     If Peek(this.conditionAddress, vbBoolean) Then 'check if val has changed         stopTicking         RaiseEvent Complete     ElseIf timer > this.endTime Then         stopTicking         RaiseEvent Timeout     Else         RaiseEvent Tick     End If End Sub  Private Sub Class_Terminate()     stopTicking End Sub 6  

Esto funciona también, pero creo que la primera versión es más en punto.

Siempre estoy luchando por la pythondad óptima, pero no estoy de ninguna manera un codificador experimentado.

Por favor comenta.

Original en ingles

The function below takes a datestring in the form d-mmm-yyyy and converts it to ISO date format (yyyy-mm-dd). Delimiters may be hyphen, space or /, and Dutch or English month abbreviations may be used.

Now, I know there is dateutil, but it returns unknown string format if you try to parse something with a non-English month in it. I haven't digested all its documentation, but I think dateutil is mainly intended for date calculation. I'm not doing that, I'm just cleaning up user input.

So I wrote my own.

import re . .  def ISOdate(date):      '''         converts the following date string format to ISO (yyyy-mm-dd):           28-okt-1924 (dutch month abbreviations)         28 oct 1924 (english..)           9/nov/2012 (single digit)     '''      shortmonths = [         'jan', 'feb', 'mrt', 'apr', 'mei', 'jun',          'jul', 'aug', 'sep', 'okt', 'nov', 'dec',          'jan', 'feb', 'mar', 'apr', 'may', 'jun',          'jul', 'aug', 'sep', 'oct', 'nov', 'dec'         ]       # Month abbrevs are only different march, may and october.                   pat = r'(\d{1,2})\s?[-\/]?\s?(\w{3})\s?[-\/]?\s?(\d{4})'      q = re.match(pat, date)     if q:          year = q.group(3)         day = int(q.group(1))          month = shortmonths.index(q.group(2).lower()) % 12 + 1         return u'{}-{:02d}-{:02d}'.format(year, month, day)     else:         # just return input, date fields may be empty         return date 

The regex match parses date month and year may not be pretty, but it works and it's easy to expand for other patterns. Likewise for the month number lookup with index, which is more concise than a chain of if, elif to match month strings to numbers.

Instead of the code between if q: and else:, I also had this, which uses datetime:

year = int(q.group(3)) day = int(q.group(1)) month = shortmonths.index(q.group(2).lower()) % 12 + 1 d = datetime.datetime(year, month, day) return u'{:%YY-%m-%d}'.format(d) 

This works too, but I think the first version is more to-the-point.

I'm always striving for optimal Pythonicness, but I'm by no means a seasoned coder.

Please comment.

        

Lista de respuestas

2
 
vote

cosas limpias.

Sugerencias:

Cambio shortmonths a un diccionario. Esto permitirá un par entre meses numéricos y meses alfabéticos. No es necesario repetir 'Jan', por ejemplo, como lo tiene ahora.

Pythonic: desempaquete month, year, day en un forro.

Uso datetime 'S strftime Para formatear fechas ... hace que la vida sea más fácil en caso de que desee cambiar el formato en la carretera.

  import re import datetime  def ISOdate(date):      month_d = {'01': 'jan',                '02': 'feb',                '03': ['mar', 'mrt'],                '04': 'apr',                '05': ['may', 'mei'],                '06': 'jun',                '07': 'jul',                '08': 'aug',                '09': 'sep',                '10': ['oct', 'okt'],                '11': 'nov',                '12': 'dec'                }       pat = r'(d{1,2})s?[-/]?s?(w{3})s?[-/]?s?(d{4})'      q = re.match(pat, date)       if q:          day, month, year = [q.group(idx+1) for idx in range(3)]          if month.isalpha(): # change from letters to numbers              month = [k for k, v in month_d.items() if month in v][0]          out_date = datetime.date(int(year), int(month), int(day))          return datetime.datetime.strftime(out_date, '%Y-%m-%d')         else:          return date       
 

Neat stuff.

Suggestions:

Changing shortmonths to a dictionary. This will allow for a pair between numerical months and alphabetical months. No need to repeat 'jan' for example, as you have it now.

Pythonic: unpack month, year, day in a one liner.

Use datetime's strftime to format dates...makes life easier in case you want to change the format down the road.

import re import datetime  def ISOdate(date):      month_d = {'01': 'jan',                '02': 'feb',                '03': ['mar', 'mrt'],                '04': 'apr',                '05': ['may', 'mei'],                '06': 'jun',                '07': 'jul',                '08': 'aug',                '09': 'sep',                '10': ['oct', 'okt'],                '11': 'nov',                '12': 'dec'                }       pat = r'(\d{1,2})\s?[-\/]?\s?(\w{3})\s?[-\/]?\s?(\d{4})'      q = re.match(pat, date)       if q:          day, month, year = [q.group(idx+1) for idx in range(3)]          if month.isalpha(): # change from letters to numbers              month = [k for k, v in month_d.items() if month in v][0]          out_date = datetime.date(int(year), int(month), int(day))          return datetime.datetime.strftime(out_date, '%Y-%m-%d')         else:          return date     
 
 
1
 
vote

Algunos comentarios / sugerencias:

  • Utilice nombres variables más largos para mejorar la legibilidad. Por ejemplo: pat - & gt; pattern , q - & gt; match , idx - & gt; & gt; month, year, day0 .
  • Trate de seguir pep257 para docstrings
  • ¿Por qué devolver la misma entrada si no era posible analizar una fecha? ¿Qué pasa con devolver month, year, day1 o tal vez recaudación de un month, year, day2 ?
  • Las expresiones regulares siempre serán difíciles de leer, pero los nombres de grupos se pueden usar para evitar los números de grupo de codificación dura más tarde:

      month, year, day3  

Finalmente, si month, year, day4 ya está haciendo un buen trabajo para las cuerdas que desea analizar, excepto las cadenas del mes, qué pasa con reemplazar las abreviaturas holandesas con los ingleses y pase la cadena a 99887766555443315 ?

  month, year, day6  
 

A few comments/suggestions:

  • Use longer variable names to improve readability. For example: pat -> pattern, q -> match, idx -> index.
  • Try to follow pep257 for docstrings
  • Why return the same input if it wasn't possible to parse a date? What about returning None or maybe raising a ValueError exception?
  • Regular expressions will always be hard to read, but group names can be used to avoid hardcoding group numbers later:

    pattern = r'(?P<day>\d{1,2})\s?[-\/]?\s?(?P<month>\w{3})\s?[-\/]?\s?(?P<year>\d{4})'  match = re.match(pat, date) if match:     year = int(match.group('year'))     month = match.group('month')     day = int(match.group('day')) 

Finally, if dateutil.parser.parse is already doing a good job for the strings you want to parse except for the month strings, what about replacing the dutch abbreviations with english ones an pass the string to dateutil.parser.parse?

import dateutil.parser  def ISO_date(date):     """Convert date string format to ISO (yyyy-mm-dd).      Examples:         28-okt-1924 (dutch month abbreviations)         28 oct 1924 (english..)          9/nov/2012 (single digit)     """     months = {         'mrt': 'mar',         'mei': 'may',         'okt': 'oct',     }      for month_dutch, month_english in months.items():         date = date.replace(month_dutch, month_english)      return dateutil.parser.parse(date)  print ISO_date('28-okt-1924') 
 
 

Relacionados problema

8  Dir = "AUTO" JavaScript Shim para IE  ( Dir auto javascript shim for ie ) 
motivo de guión: dir="auto" es un valor de atributo de la especificación HTML 5 con el soporte deficiente actual en IE y los navegadores de la Ópera . E...

1  Mostrando destinos disponibles usando angular.js  ( Displaying available destinations using angular js ) 
Me pregunto si hay algún mal olor a mi práctica para I18N en Angular. Puse la función de traducción I18N en el controlador angular (porque no sé cómo ponerlo ...

3  Traductor I18N usando Jinja2  ( I18n translator using jinja2 ) 
Estoy aprendiendo a Jinja2 y lo que es importante en este caso no es de velocidad, pero las traducciones y la funcionalidad I18n. Con Python 2.7, Jinja2 y no ...

2  PEQUEÑO: configuración regional  ( Small setting locale ) 
Soy nuevo en rieles / Ruby y me gustaría obtener comentarios sobre mi pequeño 99887766655443312 que puede detectar el idioma del visitante. Estoy especialme...

4  Detección de idioma Script PHP  ( Language detection php script ) 
Estoy trabajando en una página web con la detección de idiomas y tengo el siguiente script hasta ahora (es simple). Todavía no he hecho la detección de usuari...

15  Uno, dos, tres, ... un, deux, trois, ..., maxbound :: int  ( One two three un deux trois maxboundint ) 
Escribí una números -El convertidor de palabras para el inglés, luego intentó adaptar el código para trabajar para el francés. Me pregunto principalmente ...

16  Convertir dígitos persas a números de inglés  ( Convert persian digits to english numbers ) 
Utilizo el siguiente código para convertir ۱۲۳۴۵ a 12345 , translitiendo efectivamente los números persas en los números latinos: String.prototype.toEng...

0  ¿Cómo almacenar y acceder a piezas de texto traducidas de idioma?  ( How to store and access translated language text pieces ) 
Estamos trabajando para traducir nuestro sitio en diferentes idiomas. Actualmente, tiramos del 80% de una página de una base de datos que ya está traducida. C...

8  Código relacionado con la localidad: ¿hay casos de esquina que no vi?  ( Locale related code are there corner cases i didnt see ) 
Esta es una clase de utilidad que tengo en uno de mis proyectos y busco comentarios sobre él. He leído el javadoc para Locale varias veces mientras desarr...

8  Carga web de imágenes con nombre cirílico  ( Web uploading of cyrillic named images ) 
Para la carga web de imágenes con nombre Cirílico, he escrito el script a continuación: #!/usr/bin/python # coding=utf-8 import os import argparse import ...




© 2022 respuesta.top Reservados todos los derechos. Centro de preguntas y respuestas reservados todos los derechos