mengembalikan string dengan ekspresi reguler pertama


90

Saya ingin mendapatkan kecocokan regex pertama.

Dalam hal ini, saya mendapat daftar:

text = 'aa33bbb44'
re.findall('\d+',text)

['33', '44']

Saya bisa mengekstrak elemen pertama dari daftar:

text = 'aa33bbb44'
re.findall('\d+',text)[0]

'33'

Tapi itu hanya berfungsi jika ada setidaknya satu kecocokan, jika tidak, saya akan mendapatkan kesalahan:

text = 'aazzzbbb'
re.findall('\d+',text)[0]

IndexError: daftar indeks di luar jangkauan

Dalam hal ini saya dapat mendefinisikan suatu fungsi:

def return_first_match(text):
    try:
        result = re.findall('\d+',text)[0]
    except Exception, IndexError:
        result = ''
    return result

Apakah ada cara untuk mendapatkan hasil tersebut tanpa mendefinisikan fungsi baru?


Bagi saya jawaban yang diterima tidak berhasil. Saya harus menghapus akses indeks array dan menggunakan len(re.findAll)==0cek sebagai gantinya.
Vishal

Jawaban:


104

Anda bisa menyematkan ''default di regex Anda dengan menambahkan |$:

>>> re.findall('\d+|$', 'aa33bbb44')[0]
'33'
>>> re.findall('\d+|$', 'aazzzbbb')[0]
''
>>> re.findall('\d+|$', '')[0]
''

Juga bekerja dengan yang re.searchditunjukkan oleh orang lain:

>>> re.search('\d+|$', 'aa33bbb44').group()
'33'
>>> re.search('\d+|$', 'aazzzbbb').group()
''
>>> re.search('\d+|$', '').group()
''

Bagus, apakah search / .group memiliki keunggulan dibandingkan findall / [0]?
Luis Ramon Ramirez Rodriguez

6
@LuisRamonRamirezRodriguez Baik itu dapat berhenti segera setelah menemukan kecocokan, tidak harus memproses sisa teks dan tidak harus menyimpan semua kecocokan. Jadi lebih hemat. Juga, secara harfiah "adalah apa yang Anda inginkan" , seperti yang dikatakan @TimPeters. Itu mungkin keuntungan ketika Anda atau orang lain pada suatu saat membacanya dan bertanya-tanya "Mengapa findalldigunakan?" .
Stefan Pochmann

43

Jika Anda hanya membutuhkan kecocokan pertama, gunakan re.searchsebagai pengganti re.findall:

>>> m = re.search('\d+', 'aa33bbb44')
>>> m.group()
'33'
>>> m = re.search('\d+', 'aazzzbbb')
>>> m.group()
Traceback (most recent call last):
  File "<pyshell#281>", line 1, in <module>
    m.group()
AttributeError: 'NoneType' object has no attribute 'group'

Kemudian Anda dapat menggunakan msebagai kondisi pemeriksaan sebagai:

>>> m = re.search('\d+', 'aa33bbb44')
>>> if m:
        print('First number found = {}'.format(m.group()))
    else:
        print('Not Found')


First number found = 33

12

Saya akan pergi dengan:

r = re.search("\d+", ch)
result = return r.group(0) if r else ""

re.searchhanya mencari kecocokan pertama dalam string, jadi saya pikir itu membuat niat Anda sedikit lebih jelas daripada menggunakan findall.


7

Anda tidak boleh menggunakan .findall()sama sekali - .search()itu yang Anda inginkan. Ia menemukan kecocokan paling kiri, yang Anda inginkan (atau mengembalikan Nonejika tidak ada kecocokan).

m = re.search(pattern, text)
result = m.group(0) if m else ""

Apakah Anda ingin memasukkannya ke dalam suatu fungsi terserah Anda. Tidak biasa ingin mengembalikan string kosong jika tidak ada kecocokan yang ditemukan, itulah sebabnya tidak ada yang seperti itu yang ada di dalamnya. Tidak mungkin untuk bingung tentang apakah .search()menemukan kecocokan sendiri (ia kembali Nonejika tidak, atau SRE_Matchobjek jika itu terjadi).


3

Anda dapat melakukan:

x = re.findall('\d+', text)
result = x[0] if len(x) > 0 else ''

Perhatikan bahwa pertanyaan Anda tidak sepenuhnya terkait dengan regex. Sebaliknya, bagaimana Anda dengan aman menemukan elemen dari sebuah array, jika tidak ada.


2
Saya akan mengganti 'len (x)> 0' dengan 'x' di sini.
Ulf Aslak

1

Mungkin ini akan bekerja sedikit lebih baik jika jumlah data input yang lebih besar tidak berisi bagian yang Anda inginkan karena kecuali memiliki biaya yang lebih besar.

def return_first_match(text):
    result = re.findall('\d+',text)
    result = result[0] if result else ""
    return result
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.