【问题标题】:Python: How to add/subtract a number only to numeric characters in a string?Python:如何仅对字符串中的数字字符添加/减去数字?
【发布时间】:2017-07-30 22:23:36
【问题描述】:

例如,我有以下字符串和一个输入 4.0,它代表秒:

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

并希望得到以下结果:

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

如何识别第一行中的 hours:minutes:seconds 和其余部分中的 #.### 以添加/减去输入数字?

提前感谢您,并将接受/支持答案

【问题讨论】:

  • 试试正则表达式。
  • 第二行和第三行的数字代表什么?还有时间或浮点数?
  • @lordingtar 拆分和剥离,但找不到正确的答案。
  • 不要尝试正则表达式。您需要将 HH:MM:SS 部分解析为时间对象,对它们进行数学运算并转换回相同的格式。
  • @lmichelbacher 只是几秒钟,所以 1.001 是 1 秒,2.005 是 2 秒。所有的行都是字符串,并且认为我们应该转换为浮点数然后进行计算,然后将其转换回字符串。

标签: python string numeric alphanumeric


【解决方案1】:

如果您的完整数据与您提供的此特定示例具有相同的格式,则此解决方案应该可以工作。您应该在 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)

【讨论】:

  • 在我赞成/接受答案之前,您能否简要评论一下以进行澄清和学习?
  • 欣赏!在 round(float(splitted[0]) - val_to_add, 3) 中,它显示 3 个小数,但在某些情况下,如果它以 0 结尾,它会被截断并只显示 2。我怎样才能使它即使它有尾随 0,它仍然显示?
【解决方案2】:

虽然 regex 在 cmets 中不鼓励使用,但 regex 可用于将时间对象解析为 datetime.time 对象,对它们执行必要的计算,然后以所需的格式打印它们:

# 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 文件内容应为:

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

【讨论】:

  • 为了学习和理解,您能简单评论一下吗?提前谢谢!
  • 完成。当然,很高兴为您提供帮助!
  • 欣赏!但我实际上会读取一个文件,其中包含该内容作为示例。
  • 将哪些新行复制到文件中?您在 原始问题 中哪里提到了这一点?您要完成的完成任务是什么?我们完成的每个步骤都有另一项任务,您的原始问题中没有提到
  • 不,我们不能自动假设任何事情,数据可以来自许多来源,并且可以使用新数据,但是 您指定,在编码中您需要明确.如您所见,假设只会引起混乱。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-12-23
  • 2020-12-11
  • 2023-03-06
  • 2012-06-13
  • 2022-10-24
  • 2019-03-19
相关资源
最近更新 更多