2017-03-09 3 views
-1

Dites par exemple, j'ai les chaînes suivantes et une entrée 4.0, qui représente les secondes:Python: Comment ajouter/soustraire un nombre uniquement à des caractères numériques dans une chaîne?

John Time Made 11:05:20 in 2010 
5.001 Kelly #1 
6.005 Josh #8 

et je voudrais le résultat suivant:

John Time Made 11:05:24 in 2010 #Input 4.0 is added to the seconds of 11:05:20 
1.001 Kelly #1 #4.0 is subtracted from the first number 5.001 = 1.001 
2.005 Josh #8 #4.0 is subtracted from the first number 5.001 = 2.005 

Comment puis-je reconnaître le hours:minutes:seconds dans le premier ligne, et #.### dans le reste pour ajouter/soustraire le numéro d'entrée?

Nous vous remercions à l'avance et accepter/Upvote répondre

+0

Qu'avez-vous essayé jusqu'à présent? – lordingtar

+0

essayez avec des expressions régulières. –

+0

Que représentent les nombres sur les deuxième et troisième lignes? Aussi le temps ou les nombres à virgule flottante? – lmichelbacher

Répondre

0

Cette solution devrait fonctionner si vos données complète a le même format que cet échantillon que vous avez fourni. Vous devriez avoir les données dans le fichier input.txt.

val_to_add = 4 

with open('input.txt') as fin: 
    # processing first line 
    first_line = fin.readline().strip() 
    splitted = first_line.split(' ') 

    # get hour, minute, second corresponding to time (11:05:20) 
    time_values = splitted[3].split(':') 

    # seconds is the last element 
    seconds = int(time_values[-1]) 

    # add the value 
    new_seconds = seconds + val_to_add 

    # doing simple math to avoid having values >= 60 for minute and second 
    # this part probably can be solved with datetime or some other lib, but it's not that complex, so I did it in couple of lines 
    seconds = new_seconds % 60 # if we get > 59 seconds we only put the modulo as second and the other part goes to minute 
    new_minutes = int(time_values[1]) + new_seconds // 60 # if we have more than 60 s then here we'll add minutes produced by adding to the seconds 
    minutes = new_minutes % 60 # similarly as for seconds 
    hours = int(time_values[0]) + new_minutes // 60 

    # here I convert again to string so we could easily apply join operation (operates only on strings) and additionaly add zero in front for 1 digit numbers 
    time_values[0] = str(hours).rjust(2, '0') 
    time_values[1] = str(minutes).rjust(2, '0') 
    time_values[2] = str(seconds).rjust(2, '0') 

    new_time_val = ':'.join(time_values)# join the values to follow the HH:MM:SS format 
    splitted[3] = new_time_val# replace the old time with the new one (with the value added) 
    first_line_modified = ' '.join(splitted)# just join the modified list 

    print(first_line_modified) 

    # processing othe lines 
    for line in fin: 
     # here we only get the first (0th) value and subtract the val_to_add and round to 3 digits the response (to avoid too many decimal places) 
     stripped = line.strip() 
     splitted = stripped.split(' ') 
     splitted[0] = str(round(float(splitted[0]) - val_to_add, 3)) 
     modified_line = ' '.join(splitted) 
     print(modified_line) 
+0

Avant que j'ai upvote/accepter la réponse, pourriez-vous commenter brièvement à des fins de clarification et d'apprentissage? –

+0

J'ai mis à jour la réponse avec des commentaires – giliev

+0

Appréciez-le! En round (float (split [0]) - val_to_add, 3), il montre 3 décimales mais sur certaines, s'il se termine par 0, il est coupé et ne montre que 2. Comment puis-je faire en sorte que même s'il a après 0, ça montre encore? –

0

Bien que regex, regex a été découragée dans les commentaires peuvent être utilisés pour analyser le temps des objets dans datetime.time objets, effectuer les calculs nécessaires sur eux, puis les imprimer dans le format requis:

# datetime module for time calculations 
import datetime 
# regex module 
import re 

# seconds to add to time 
myinp = 4 

# List of data strings 
# data = 'John Time Made 11:05:20 in 2010', '5.001 Kelly', '6.005 Josh' 

with open('data.txt') as f: 
    data = f.readlines() 

new_data = [] 

#iterate through the list of data strings 
for time in data: 
    try: 
     # First check for 'HH:MM:SS' time format in data string 
     # regex taken from this question: http://stackoverflow.com/questions/8318236/regex-pattern-for-hhmmss-time-string 
     match = re.findall("([0-1]?\d|2[0-3]):([0-5]?\d):([0-5]?\d)", time) 
     # this regex returns a list of tuples as strings "[('HH', 'MM', 'SS')]", 
     # which we join back together with ':' (colon) separators 
     t = ':'.join(match[0]) 
     # create a Datetime object from indexing the first matched time in the list, 
     # taken from this answer http://stackoverflow.com/questions/100210/what-is-the-standard-way-to-add-n-seconds-to-datetime-time-in-python 
     # May create an IndexError exception, which we catch in the `except` clause below 
     orig = datetime.datetime(100,1,1,int(match[0][0]), int(match[0][1]), int(match[0][2])) 
     # Add the number of seconds to the Datetime object, 
     # taken from this answer: http://stackoverflow.com/questions/656297/python-time-timedelta-equivalent 
     newtime = (orig + datetime.timedelta(0, myinp)).time() 
     # replace the time in the original data string with the newtime and print 
     new_data.append(time.replace(t, str(newtime))) 
    # catch an IndexError Exception, which we look for float-formatted seconds only 
    except IndexError: 
     # look for float-formatted seconds (s.xxx)  
     # taken from this answer: http://stackoverflow.com/questions/4703390/how-to-extract-a-floating-number-from-a-string 
     match = re.findall("\d+\.\d+", time) 
     # create a Datetime object from indexing the first matched time in the list, 
     # specifying only seconds, and microseconds, which we convert to milliseconds (micro*1000) 
     orig = datetime.datetime(100,1,1,second=int(match[0].split('.')[0]),microsecond=int(match[0].split('.')[1])*1000) 
     # Subtract the seconds from the Datetime object, similiar to the time addtion in the `try` clause above 
     newtime = orig - datetime.timedelta(0, myinp) 
     # format the newtime as `seconds` concatenated with the milliseconds converted from microseconds 
     newtime_fmt = newtime.second + newtime.microsecond/1000000. 
     # Get the seconds value (first value(index 0)) from splitting the original string at the `space` between the `seconds` and `name` strings 
     t = time.split(' ')[0] 
     # replace the time in the original data string with the newtime and print 
     new_data.append(time.replace(t , str(newtime_fmt))) 


with open('new_data.txt', 'w') as nf: 
    for newline in new_data: 
     nf.write(newline) 

new_data.txt le contenu du fichier devrait se lier comme:

John Time Made 11:05:24 in 2010 
1.001 Kelly 
2.005 Josh 
+0

à des fins d'apprentissage et de compréhension, pourriez-vous commenter brièvement? Merci d'avance! –

+0

Terminé. Bien sûr, heureux d'aider! – davedwards

+0

Appréciez-le! Mais je vais effectivement lire un fichier qui contient ce contenu comme exemple. –