Как найти номер из текста - PullRequest
2 голосов
/ 20 октября 2019

Это небольшой пример столбца pyspark (String) в моем фрейме данных.

 column                                                                                            |   new_column
------------------------------------------------------------------------------------------------- |--------------------------------------------------
Hoy es día 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]
------------------------------------------------------------------------------------------------- |--------------------------------------------------
ciencia ABC/KE2646/L61175:E/F-levanta con sueño L61/62LAV AT Z5CTR/XC D3-1593                     |    [2646]
-----------------------------------------------------------------------------------------------------------------------------------------------------
escuela ABCS 6048/206049/6050/206051/205225-FG-matemáticas- MSN 2345                              |    [6048,206049,6050,206051,205225]
-----------------------------------------------------------------------------------------------------------------------------------------------------
FOR ABC/KE 109038_L35674_DEFINE AND DESIGN IMPROVEMENTS OF 1618 FROM 118(PDS4 BRACKETS)           |   [109038]
-----------------------------------------------------------------------------------------------------------------------------------------------------
y comienza FOR ABC- 2981 / KE T79581: el camino hacia la 9856                                     |   [2981]

Я хочу извлечь из этого текста все числа, содержащие: 4, 5 или 6 цифр. Условие и случаи для их извлечения:

- Attached to ABC/KE (first line in the example above).
- after ABC/KE + space (second and third line).
- after ABC + space (line 4)
- after ABC without space (line 5)
- after ABC - KE + space
- after for word
- after ABC- + space
- after ABC + space
- after ABCS (line 10 and 11)

Пример невыполненных дел:

                                    Column                                                    |   new_column
------------------------------------------------------------------------------------------------------------------------
FOR ABC/KE 109038_L35674_DEFINE AND DESIGN IMPROVEMENTS OF 1618 FROM 118(PDS4 BRACKETS)           |   [1618]   ==> should be [109038]
------------------------------------------------------------------------------------------------------------------------
ciencia ABC/KE2646/L61175:E/F-levanta con sueño L61/62LAV AT Z5CTR/XC D3-1593                     |   [1593]  ==> should be [2646]
------------------------------------------------------------------------------------------------------------------------
escuela ABCS 6048/206049/6050/206051/205225-FG-matemáticas- MSN 2345                              |    [6048,206049,6050,206051,205225, 2345]  ==> should be [6048,206049,6050,206051,205225]

Я надеюсь, что я возобновил дела, вы можете увидеть мой пример выше и ожидаемый результат. Как я могу это сделать ? Спасибо

1 Ответ

3 голосов
/ 20 октября 2019

Один из способов использования регулярных выражений для очистки данных и установки одиночного якоря со значением 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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...