Как сохранить номер в тексте - PullRequest
0 голосов
/ 15 октября 2019

У меня есть дата-фрейм pyspark, я хотел бы улучшить приведенное ниже регулярное выражение. Я хочу добавить условие или изменить регулярное выражение:

  • восстановить все числа, которые в конце присоединены к / или letter.

Примерof case1:

column_example                                        |   new_column
------------------------------------------------------|-----------------                                       |
mundo por el número de NJU/LOK 12345T98789-hablantes  |   12345
hispanohablantes ZES/UJ86758/L87586:residentes en     |   86758

Пример case 2:

  • Я не должен брать число, которое пришло после слова ABC.

Пример столбца:

    My_column                                             |         new_column
------------------------------------------------------|---------------------
mundo por el número de ABC 8567 hablantes             |           []
------------------------------------------------------|---------------------
con dominio nativo ABC 987480 millones de personas    |           []
------------------------------------------------------|---------------------
hispanohablantes residentes en ABC98754 otros países  |           []

Следующий код:

ptn = re.complie(r'^(?:MOD)?[0-9]{4,6}$')
array_filter = udf(lambda arr: [ x.lstrip('MOD') for x in arr if re.match(ptn, x) ] if type(arr) is list else arr, ArrayType(StringType()))

Как я могу это сделать? Спасибо

1 Ответ

2 голосов
/ 15 октября 2019

В одну сторону без использования udf для Spark до версии 2.4.0 :

from pyspark.sql.functions import split, regexp_replace

df.withColumn('new_column'
   , split(
       regexp_replace(
           regexp_replace('My_column', r'.*?(?<!ABC\s{0,5})(?<!\d)(\d{4,6})(?=[A-Z/])', '$1\0')
         , '\0?[^\0]*$'
         , ''
       )
     ,'\0')
   ) \
  .show(truncate=False)
+-----------------------------------------------------------------------+--------------+
|My_column                                                              |new_column    |
+-----------------------------------------------------------------------+--------------+
|23458/ mundo por el nmero de NJU/LOK 12345T98789 hablantes             |[23458, 12345]|
|con dominio nativo ABC 987480 millones ZES/UJ86758/L87586:residentes en|[86758]       |
|hispanohablantes  residentes en ABC98754/ otros pases                  |[]            |
+-----------------------------------------------------------------------+--------------+

Где:

  • использовать regexp_replace: заменить текст, соответствующий следующему шаблону

    .*?(?<!ABC\s{0,5})(?<!\d)(\d{4,6})(?=[A-Z/])
    

на $1\0, который удаляет весь несвязанный текст до NUMBER_NEEDED (сохранено в $ 1 ), которому не предшествуют ABC\s{0,5} и \d, а затем [A-Z/]. поместите NULL char \0 в конце каждого соответствующего $1.

  • используйте split(text, '\0') для преобразования вышеуказанного текста в массив, обратите внимание, что последний элемент массиване имеет значения, которое следует исключить

  • используйте другой regexp_replace(text, '\0?[^\0]*$', '') для удаления конечного несвязанного текста перед запуском вышеуказанной функции split ()

Примечания:

  • (?<!ABC\s{0,5}) позволит протестировать 0-5 пробелов между ABC и NUMBER_NEEDED . Так как регулярное выражение отрицательное lookbehind не поддерживает (?<!ABC\s*), если ваш текст может содержать больше пробелов, вы можете настроить 5 на большее число. КСТАТИ. (?<!ABC\s{0,5}) подходит для PySpark, но недопустим в модуле Python re, который допускает только шаблон фиксированной ширины

  • prepend (?s), чтобы разрешить режим точек, если любой текст содержит разрывы строк

  • Я предположил, что NULL char \0 не отображается в ваших исходных текстах, так как он не будет частью совпадений, вы можете удалить их все (regexp_replace(text, '\0', '')) перед запуском вышеуказанного 3функции.

Другой способ использования udf:

import re
from pyspark.sql.types import ArrayType, StringType
from pyspark.sql.functions import udf

ptn = re.compile(r'(?<!ABC)(?<!\d)(\d{4,6})(?=[A-Z/])')

find_number = udf(lambda x: re.findall(ptn, re.sub(r'(?<=ABC)\s+', '', x)) if x else [], ArrayType(StringType()))

df.withColumn('new_column', find_number('My_column')).show()
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...