簡體   English   中英

在某個字符后從字符串中提取數字

[英]Extract a number from a string, after a certain character

好的,我需要一些幫助。 我有以下字符串,始終采用“ char,num”格式:

s = "abcdef,12"
v = "gbhjjj,699"

我只想獲取逗號后的數字,如何在不使用逗號分隔字符串的情況下做到這一點呢?

我嘗試了s[-2:]v[-3:]可以工作,但是如何在不知道位數的情況下使其工作呢?

假設:

  • 知道字符串中有一個逗號,因此您不必搜索整個字符串來查找是否存在逗號。
  • 您知道模式是'many_not_digits,few_digits'因此逗號兩側左右部分的大小之間存在很大的不平衡。
  • 您無需走就可以到達字符串的末尾,這在Python中是可以的,因為字符串索引是固定時間的

然后,你可以從月底開始,步行向后尋找逗號,這將是你的例子不是從左邊尋找逗號走整體工作量少。

使用Python代碼進行工作比使用C語言編寫的Python引擎代碼要慢得多,對吧? 真的會更快嗎?

  1. 制作一個字符串“ aaaaa ....,12”
  2. 使用timeit模塊比較每種方法-拆分或右移。
  3. Timeit可以執行一百萬次某些代碼。
  4. 延長“ aaaaaaaaaaaaaaaaaa ....,12”的長度以使其極端。

他們如何比較?

  • 字符串拆分:1400次“ a”的運行一百萬次耗時1秒。
  • 字符串拆分:4000次“ a”的運行100萬次耗時2秒。
  • 右行走:1400次“ a”的跑步一百萬次耗時0.4秒。
  • 右走:999,999“ a”的運行時間為一百萬次,耗時為0.4秒。

from timeit import timeit

_split = """num = x.split(',')[-1]"""

_rwalk = """
i=-1
while x[i] != ',':
    i-=1
num = x[i+1:]
"""

print(timeit(_split, setup='x="a"*1400 + ",12"'))
print(timeit(_rwalk, setup='x="a"*999999 + ",12"'))

例如

1.0063155219977489     # "aaa...,12" for 1400 chars, string split
0.4027107510046335     # "aaa...,12" for 999999 chars, rwalked. Faster.

在repl.it在線嘗試

我認為這在算法上並不比O(n)更好,但是在假設的約束下,我使您比str.split()擁有更多的知識,並且可以利用它來跳過大部分字符串並擊敗它在實踐中-文本部分越長,數字部分越短,您就越受益。

如果由於一開始有很多多余的字符而擔心從左側使用split,請使用rsplit。

s = "abcdef,12"
s.rsplit(",", 1)[-1]

在這里,rsplit將開始從右邊開始拆分字符串,我們使用的可選第二個參數將停止rsplit繼續進行處理,而不是它遇到的第一個逗號運算符。

(eg):
s = "abc,def,12"
s.rsplit(",", 1)[-1]
# Outputs 12
s = "abcdef12"
s.rsplit(",", 1)[-1]
# Outputs abcdef12

最終獲得一串數字比手動進行操作要簡單得多,也更清潔。

更不用說,如果我們希望檢查是否僅由此得到數字,則將容易得多。 即使它是字符串列表。

def get_numbers(string_list, skip_on_error=True):
    numbers_list = []
    for input_string in string_list:
        the_number = input_string.rsplit(",", 1)[-1]
        if the_number.isdigit():
            numbers_list.append(the_number)
        elif skip_on_error:
            numbers_list.append("")
        else:
            raise Exception("Wrong Format occurred: %s" % (input_string))
    return numbers_list

而且,如果您正在尋找進一步的優化方法,並確保大多數(如果不是全部)字符串都具有正確的格式,則可以使用try,除非您打算使用整數列表而不是字符串列表。 像這樣:

# Instead of the if.. elif.. else construct
try:
    numbers_list.append(int(the_number))
except ValueError:
    if skip_on_error:
        numbers_list.append(0)
    else:
        raise Exception("Wrong Format occurred: %s" % (input_string))

但請始終記住PythonZen,並按照以下方法使用split / rsplit:

  1. 美麗勝於丑陋
  2. 顯式勝於隱式
  3. 簡單勝於復雜
  4. 可讀性計數
  5. 應該有一種-最好只有一種-顯而易見的方法

還要記住唐納德·克努斯(Donald Knuth):

大約有97%的時間,我們應該忘掉效率低下的問題: 過早的優化是萬惡之源 但是我們不應該放棄我們那關鍵的3%的機會

使用split的優勢在於它非常清晰,快速:

>>> s = "abcdef,12"
>>> s.split(',')[1]
'12'

另一種方法是使用indexfind

>>> s = "abcdef,12"
>>> s[s.find(',')+1:]
'12'

和另一種方式與re

>>> import re
>>> s = "abcdef,12"
>>> re.search(r',(.*)', s).group(1)
'12'

並使用csv (和io因此我不必將文件寫入硬盤驅動器):

>>> import csv
>>> import io
>>> s = "abcdef,12"
>>> r = csv.reader(i)
>>> for line in r:
...     print(line[1])
...
12

我確定還有其他方法可以完成此任務。 這只是一個小樣本。

也許您可以嘗試使用正則表達式

import re

input_strings = ["abcdef,12", "gbhjjj,699"]

matcher = re.compile("\d+$")

for input_string in input_strings:
    is_matched = matcher.search(input_string)
    if is_matched:
        print(is_matched.group())

我喜歡.partition()做這種事情:

for text in ('gbhjjj,699', 'abcdef,12'):

    x, y, z = text.partition(',')

    number = int(z)

    print(number)

.split()不同,它將始終返回三個值。

我有時會這樣做,以強調我不在乎某些值:

_, _, z = text.partition(',')

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM