テキストファイルまたは文字列からスペースを含むすべての非数値文字を削除し、新しい結果を古い文字の横に出力するタスクが与えられました。たとえば、次のようになります。
前:
sd67637 8
後:
676378
私は初心者なので、このタスクをどこから始めればよいかわかりません。助けてください
テキストファイルまたは文字列からスペースを含むすべての非数値文字を削除し、新しい結果を古い文字の横に出力するタスクが与えられました。たとえば、次のようになります。
前:
sd67637 8
後:
676378
私は初心者なので、このタスクをどこから始めればよいかわかりません。助けてください
最も簡単な方法は、正規表現を使用することです
import re
a = 'lkdfhisoe78347834 (())&/&745 '
result = re.sub('[^0-9]','', a)
print result
>>> '78347834745'
文字列を 1 文字ずつループし、数字のみを含めます。
new_string = ''.join(ch for ch in your_string if ch.isdigit())
または、文字列に正規表現を使用します(ある時点で、連続していないグループを個別に扱いたい場合)...
import re
s = 'sd67637 8'
new_string = ''.join(re.findall(r'\d+', s))
# 676378
次に、print
それらだけを取り出します。
print(old_string, '=', new_string)
これにはビルトインがあります。
string.translate(s, table[, deletechars])
deletechars (存在する場合) にある s からすべての文字を削除し、table を使用して文字を変換します。これは、各文字値の変換を与える 256 文字の文字列で、序数によってインデックス付けされている必要があります。table が None の場合、文字削除ステップのみが実行されます。
>>> import string
>>> non_numeric_chars = ''.join(set(string.printable) - set(string.digits))
>>> non_numeric_chars = string.printable[10:] # more effective method. (choose one)
'sd67637 8'.translate(None, non_numeric_chars)
'676378'
または、インポートなしでそれを行うこともできます (ただし、これには理由はありません)。
>>> chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~ \t\n\r\x0b\x0c'
>>> 'sd67637 8'.translate(None, chars)
'676378'
これには正規表現を使用しません。それはずっと遅いです!
for
代わりに、単純なループを使用しましょう。
この機能により、仕事が速く完了します...
def filter_non_digits(string: str) -> str:
result = ''
for char in string:
if char in '1234567890':
result += char
return result
提案されているいくつかの異なる方法をテストするための非常に基本的なベンチマークを作成しましょう。3つの方法をテストします...
# filters.py
import re
# For loop method
def filter_non_digits_for(string: str) -> str:
result = ''
for char in string:
if char in '1234567890':
result += char
return result
# Comprehension method
def filter_non_digits_comp(s: str) -> str:
return ''.join(ch for ch in s if ch.isdigit())
# RegEx method
def filter_non_digits_re(string: str) -> str:
return re.sub('[^\d]','', string)
数字を削除する各方法の実装ができたので、それぞれをベンチマークしましょう。
以下は、非常に基本的で初歩的なベンチマーク コードです。ただし、それはトリックを実行し、各メソッドのパフォーマンスを適切に比較できます。
# tests.py
import time, platform
from filters import filter_non_digits_re,
filter_non_digits_comp,
filter_non_digits_for
def benchmark_func(func):
start = time.time()
# the "_" in the number just makes it more readable
for i in range(100_000):
func('afes098u98sfe')
end = time.time()
return (end-start)/100_000
def bench_all():
print(f'# System ({platform.system()} {platform.machine()})')
print(f'# Python {platform.python_version()}\n')
tests = [
filter_non_digits_re,
filter_non_digits_comp,
filter_non_digits_for,
]
for t in tests:
duration = benchmark_func(t)
ns = round(duration * 1_000_000_000)
print(f'{t.__name__.ljust(30)} {str(ns).rjust(6)} ns/op')
if __name__ == "__main__":
bench_all()
ベンチマーク コードからの出力を次に示します。
# System (Windows AMD64)
# Python 3.9.8
filter_non_digits_re 2920 ns/op
filter_non_digits_comp 1280 ns/op
filter_non_digits_for 660 ns/op
ご覧のfilter_non_digits_for()
とおり、関数は RegEx を使用するよりも 4 倍以上高速であり、理解メソッドよりも約 2 倍高速です。時にはシンプルイズベスト。
@MoradneJad に追加します。次のコードを使用して、整数値、浮動小数点数、さらには符号付きの値を抽出できます。
a = re.findall(r"[-+]?\d*\.\d+|\d+", "Over th44e same pe14.1riod of time, p-0.8rices also rose by 82.8p")
そして、 を使用して、リスト項目を効果的に数値データ型に変換できますmap
。
print(list(map(float, a)))
[44.0, 14.1, -0.8, 82.8]