【问题标题】:Extracting an integer between = and ;提取 = 和 ; 之间的整数
【发布时间】:2012-12-06 14:53:04
【问题描述】:

给定以下字符串;

....00.3276021,,,constString1=31;garbage=00:00:00.0090000;constString2=16;garbage2=00.00...

如何提取constString1constString2 的值,以便将它们分配给变量。例如:

string1_cummulativeTotal += [the magic returning the int]
string2_cummulativeTotal += [the magic returning the int]

谢谢!

【问题讨论】:

  • 一个很好的问题是这个字符串是从哪里来的?它可能会影响答案的编写方式,如果您按照下面的建议从 CSV 中读取数据,那么您可能会有更好的解决方案,此外,如果您有可能要捕获更多“constStrings”,或者他们的顺序可能会改变,这对我们来说应该很重要。

标签: python regex file-io readline


【解决方案1】:
In [1]: import re

In [2]: s = '....00.3276021,,,constString1=31;garbage=00:00:00.0090000;constString2=16;garbage2=00.00...'

In [3]: re.search('constString1=(\d+);', s).group(1)
Out[3]: '31'

In [4]: re.search('constString2=(\d+);', s).group(1)
Out[4]: '16'

这些仍然是字符串,不要忘记将它们转换为整数。

【讨论】:

  • 请注意 \d+ 将匹配 0123 这不是一个有效的整数文字(至少在 python 方面)。
  • @khachik 就 Python 而言,它实际上似乎是一个有效的整数:int('0123') 返回 123。
  • int() 构造函数对前导 0(和空格)很聪明,是的。它不是用作整数文字,而是正在转换的字符串。
  • @LevLevitsky,不,不是:>>> 0123 导致SyntaxErrorint() 可以像 123 一样处理它,但 OP 必须确保这是预期的行为。
  • Pedantic: 0123 在 Python 2 中不是语法错误。它的值也不是 123。
【解决方案2】:

你可以不用正则表达式。

def get_sub(s, start, end):
    s1 = s[s.find(start) + len(start):]
    return s1[:s1.find(end)]

get_sub(s, "constString1=", ";")
>>> '31'

get_sub(s, "constString2=", ";")
>>> '16'

如果您想将其转换为另一种类型,您可以执行以下操作:

def get_sub(s, start, end, cast_to):
    s1 = s[s.find(start) + len(start):]
    return cast_to(s1[:s1.find(end)])

get_sub(s,"constString1=",";", int)
>>> 31

get_sub(s,"constString2=",";", float)
>>> 16.0

编辑

这种方法实际上比正则表达式更快:

t1 = timeit.Timer(stmt="""get_sub(s,"constString1=",";", int)""", setup="""s = "....00.3276021,,,constString1=31;garbage=00:00:00.0090000;constString2=16;garbage2=00.00..."
def get_sub(s, start, end, cast_to):
    s1 = s[s.find(start) + len(start):]
    return cast_to(s1[:s1.find(end)])""")

t2 = timeit.Timer(stmt="""int(re.search("constString1=(\d+);",s).group(1))""", setup="""import re
s = "....00.3276021,,,constString1=31;garbage=00:00:00.0090000;constString2=16;garbage2=00.00..."
""")

>>> t1.timeit()
2.829952681655172

>>> t2.timeit()
3.7208872074169506

【讨论】:

  • 我喜欢这种方法,但我认为它不如使用正则表达式有效。不过,很高兴看到另一个选择。
  • 使用timeit你可以看到它实际上更快。
  • 你能给我们看看吗? timeit 反对什么? - 我看到了 timeit,但那是针对单个 constStrings,我的方法同时执行它们,应该快一点。
  • 您的方法错误地假定 constString1 出现在 constString2.. 之前,并且被硬编码以适用于特定的键顺序,在我看来,这是糟糕的设计。但如果您愿意,可以将其与timeit 进行比较并分享您的发现。总的来说,我认为除非真的需要,否则最好避免使用正则表达式,只是想展示如何做到这一点。
【解决方案3】:

除了其他答案中提到的正则表达式方法之外,如果单独的项目用分号分隔,您可以使用如下代码,split(';')split('=')

s='....00.3276021,,,;constString1=31;garbage=00:00:00.0090000;constString2=16;garbage2=00.00...'
string1_subtotal = string2_subtotal = 0
for ss in s.split(';'):
    a = ss.split('=')
    if a[0]=='constString1': string1_subtotal += int(a[1])
    if a[0]=='constString2': string2_subtotal += int(a[1])

【讨论】:

  • 这绝对是一种方法,尽管它假设很多。但是 - 它非常低效,而且内存浪费,拆分会创建新的字符串,而且你正在做很多。另外,一目了然,很难看出代码在做什么,这是关于 python 的重要事情之一,对不起,-1
  • 另外,需要从 OP 更改原始字符串以插入 ;.
【解决方案4】:

为什么不一次做完呢?

>>> import re
>>> s = "....00.3276021,,,constString1=31;garbage=00:00:00.0090000;constString2=16;garbage2=00.00..."
>>> ms = re.match(r'.*constString1=(\d+);.*constString2=(\d+);', s)
>>> ms.groups() #just to show you. you wont need to do this on your code...
('31', '16') 
>>> string1_cummulativeTotal += ms.group(1)
>>> string2_cummulativeTotal += ms.group(2)

注意:这仅适用于contString 的顺序正确(1,2....)

【讨论】:

  • 假设constString1constString2 在所有字符串中的顺序相同,这将起作用。
  • 好吧,这个操作并没有让我相信。我猜这是一个选择,要么接受,要么离开。
  • 当然。输入有点像 csv,所以你的方法很可能会奏效。但我认为值得说明解决方案所基于的假设。
  • 有人至少可以解释为什么他们-1我,这是一个完全可以接受的答案,解决了OP提出的问题,并且在没有任何理由的情况下被否决了。我错过了什么吗?
  • @InbarRose,我要去没有人打电话给我的地方。但它seems 对我来说就像人们不欣赏你自以为是的态度。这只是我的 POV,因为您对这个线程中的每个问题/答案/评论都有自己的看法。不过,感谢您抽出宝贵时间提供答案和建设性意见。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-08-01
  • 1970-01-01
  • 2017-07-19
  • 1970-01-01
  • 1970-01-01
  • 2020-08-04
  • 1970-01-01
相关资源
最近更新 更多