В одну сторону без использования 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()