Один из способов использования регулярных выражений для очистки данных и установки одиночного якоря со значением ABC
для определения начала потенциального совпадения. после str.split () выполните итерацию по результирующему массиву, чтобы пометить и извлечь последовательные совпадающие номера, следующие за этим якорем.
Редактировать: Добавлено подчеркивание _
в шаблон данных (\b(\d{4,6})(?=[A-Z/_]|$)
) так что теперь он позволяет подчеркиванию в качестве якоря следовать выбранной подстроке из 4-6 цифр. это исправило первую строку, строки 2 и 3 должны работать с существующими шаблонами регулярных выражений.
import re
from pyspark.sql.types import ArrayType, StringType
from pyspark.sql.functions import udf
(1) Используйте шаблоны регулярных выражений для очистки необработанных данных, чтобы у нас был только один якорь ABC
чтобы определить начало потенциального совпадения:
clean1 : используйте [-&\s]+
для преобразования '&', '-' и пробелов в ПРОБЕЛ ' '
они используются для соединения цепочки чисел
example: `ABC - KE` --> `ABC KE`
`103035 - 101926 - 105484` -> `103035 101926 105484`
`111553/L00847 & 111558/L00895` -> `111553/L00847 111558/L00895`
clean2 : преобразовать текст, соответствующий следующим трем подэлементам, в 'ABC '
+ ABCS?(?:[/\s]+KE|(?=\s*\d))
+ ABC followed by an optional `S`
+ followed by at least one slash or whitespace and then `KE` --> `[/\s]+KE`
example: `ABC/KE 110330/L63868` to `ABC 110330/L63868`
+ or followed by optional whitespaces and then at least one digit --> (?=\s*\d)
example: ABC898456 -> `ABC 898456`
+ \bFOR\s+(?:[A-Z]+\s+)*
+ `FOR` words
example: `FOR DEF HJK 12345` -> `ABC 12345`
data : \ b (\ d {4,6}) (? = [AZ / _] | $) является регулярным выражениемдля совпадения с действительными числами: 4-6 цифр, за которыми следует [AZ /] или end_of_string
(2) Создайте команду для сохранения всех 3 рисунков:
ptns = {
'clean1': re.compile(r'[-&\s]+', re.UNICODE)
, 'clean2': re.compile(r'\bABCS?(?:[/\s-]+KE|(?=\s*\d))|\bFOR\s+(?:[A-Z]+\s+)*', re.UNICODE)
, 'data' : re.compile(r'\b(\d{4,6})(?=[A-Z/_]|$)', re.UNICODE)
}
(3) Создайте функцию для поиска совпавших чисел и сохраните их в массиве
def find_number(s_t_r, ptns, is_debug=0):
try:
arr = re.sub(ptns['clean2'], 'ABC ', re.sub(ptns['clean1'], ' ', s_t_r.upper())).split()
if is_debug: return arr
# f: flag to identify if a chain of matches is started, default is 0(false)
f = 0
new_arr = []
# iterate through the above arr and start checking numbers when anchor is detected and set f=1
for x in arr:
if x == 'ABC':
f = 1
elif f:
new = re.findall(ptns['data'], x)
# if find any matches, else reset the flag
if new:
new_arr.extend(new)
else:
f = 0
return new_arr
except Exception as e:
# only use print in local debugging
print('ERROR:{}:\n [{}]\n'.format(s_t_r, e))
return []
(4) определите функцию udf
udf_find_number = udf(lambda x: find_number(x, ptns), ArrayType(StringType()))
(5) get new_column
df.withColumn('new_column', udf_find_number('column')).show(truncate=False)
+------------------------------------------------------------------------------------------+------------------------------------------------+
|column |new_column |
+------------------------------------------------------------------------------------------+------------------------------------------------+
|Hoy es da de ABC/KE98789T983456 clase. |[98789] |
|Como ABC/KE 34562Z845673 todas las ma?anas |[34562] |
|Hoy tiene ABC/KE 110330/L63868 clase de matem篓垄ticas, |[110330] |
|Marcos se ABC 898456/L56784 levanta con sue?o. |[898456] |
|Marcos se ABC898456 levanta con sue?o. |[898456] |
|comienza ABC - KE 60014 -T60058 |[60014] |
|ingl篓娄s y FOR 102658/L61144 ciencia. Se viste, desayuna |[102658] |
|y comienza FOR ABC- 72981 / KE T79581: el camino hacia la |[72981] |
|escuela. Se FOR ABC 101665 - 103035 - 101926 - 105484 - 103036 - 103247 - encuentra con su|[101665, 103035, 101926, 105484, 103036, 103247]|
|escuela ABCS 206048/206049/206050/206051/205225-FG-matem篓垄ticas- |[206048, 206049, 206050, 206051, 205225] |
|encuentra ABCS 111553/L00847 & 111558/L00895 - matem篓垄ticas |[111553, 111558] |
|ciencia ABC 163278/P20447 AND RETROFIT ABCS 164567/P21000 - 164568/P21001 - desayuna |[163278, 164567, 164568] |
|ABC/KE 71729/T81672 - 71781/T81674 71782/T81676 71730/T81673 71783/T81677 71784/T |[71729, 71781, 71782, 71730, 71783, 71784] |
+------------------------------------------------------------------------------------------+------------------------------------------------+
(6) код для отладки, используйте find_number(row.column, ptns, 1)
, чтобы проверить, как / if первые два шаблона регулярных выражений работают должным образом:
for row in df.limit(10).collect():
print('{}:\n {}\n'.format(row.column, find_number(row.column, ptns)))
Некоторые примечания:
в шаблоне clean2
, ABCS и ABSотноситься так же. если они отличаются, просто удалите 'S' и добавьте новую альтернативу ABCS\s*(?=\d)
в конец шаблона
re.compile(r'\bABC(?:[/\s-]+KE|(?=\s*\d))|\bFOR\s+(?:[A-Z]+\s+)*|ABCS\s*(?=\d)')
текущий шаблон clean1
обрабатывает только '-', '&' и пробелы в качестве последовательного соединителя, вы можете добавить больше символов или слов, таких как 'и', 'или', например:
re.compile(r'[-&\s]+|\b(?:AND|OR)\b')
FOR words
is \ bFOR\ s + (?: [AZ] + \ s +) *, это может быть скорректировано в зависимости от того, допустимы ли числа в словах и т. д.
Это было протестировано на Python-3. при использовании Python-2 может возникнуть проблема с юникодом, вы можете исправить это, используя метод в первом ответе reference