Python RegEx для удаления номера социального страхования из строки, созданной с преобразованием речи в текст - PullRequest
1 голос
/ 02 апреля 2020

Я пытаюсь удалить номера социального страхования (SSN) по причинам, соответствующим GDPR, из грязных данных, генерируемых с преобразованием речи в текст. Вот пример строки (переведенной на английский язык sh, которая объясняет, почему 'и' происходит, когда в списке указаны номера SSN):

sample1 = "hello my name is sofie my social security number is thirteen zero four five and seventy eighteen seven and forty and I live on mountain street number twelve"

Моя цель - удалить часть "thirteen ... forty ", сохраняя при этом другие числа, которые может появиться в строке, что приведет к:

sample1_wo_ssn = "hello my name is sofie my social security number is and I live on mountain street number twelve"

Длина номера социального страхования может варьироваться в зависимости от того, как генерируются данные (3-10 разделенных номеров).

Мой подход :

  1. Замените записанные числа цифрами, используя dict
  2. Используйте регулярные выражения, чтобы найти 3 или более чисел, встречающихся только с пробелами, или "and", разделяя их, и удалите их вместе с любым числом. следуя этим 3 номерам.

Вот мой код:

import re

number_dict = {
    'zero': '0',
    'one': '1',
    'two': '2',
    'three': '3',
    'four': '4',
    'five': '5',
    'six': '6',
    'seven': '7',
    'eight': '8',
    'nine': '9',
    'ten': '10',
    'eleven': '11',
    'twelve': '12',
    'thirteen': '13',
    'fourteen': '14',
    'fifteen': '15',
    'sixteen': '16',
    'seventeen': '17',
    'eighteen': '18',
    'nineteen': '19',
    'twenty': '20',
    'thirty': '30',
    'forty': '40',
    'fifty': '50',
    'sixty': '60',
    'seventy': '70',
    'eighty': '80',
    'ninety': '90'
}


sample1 = "hello my name is sofie my social security number is thirteen zero four five and seventy eighteen seven and forty and I live on mountain street number twelve"
sample1_temp = [number_dict.get(item,item)  for item in sample1.split()]
sample1_numb = ' '.join(sample1_temp)
re_results = re.findall(r'(\d+ (and\s)?\d+ (and\s)?\d+\s?(and\s)?(\d+)?\s?(and\s)?(\d+)?\s?(and\s)?(\d+)?\s?(and\s)?(\d+)?\s?(and\s)?(\d+)?\s?(and\s)?(\d+)?\s?(and\s)?(\d+)?\s?(and\s)?(\d+)?)', sample1_numb) 

print(re_results)

Вывод:

[('13 0 4 5 and 70 18 7 and 40 and ', '', '', '', '5', 'and ', '70', '', '18', '', '7', 'and ', '40', 'and ', '', '', '', '', '')]

Вот где я застрял.

В этом примере я мог бы сделать что-то вроде sample1_wh_ssn = re.sub(re_results[0][0],'',sample1_numb), чтобы получить желаемый результат, но это не обобщает.

Любая помощь будет принята с благодарностью.

1 Ответ

1 голос
/ 02 апреля 2020

Вот реализация вашего текущего логика c, а именно:

  • Преобразование номеров слов от 1 до 99 в числа
  • Удаление всех экземпляров 3 или более чисел, разделенных пробелами
  • Преобразование чисел в два числа git обратно в слова.

Кредиты:

См. Python код :

import re

number_words = [ "zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten", "eleven", "twelve", "thirteen", "fourteen", "fifteen", "sixteen", "seventeen", "eighteen", "nineteen"]
number_words_tens =[ "twenty", "thirty", "forty", "fifty", "sixty", "seventy", "eighty", "ninety" ]
number_words_rx = re.compile(r'\b(?:(?:{0})?(?:{1})|(?:{0}))\b'.format("|".join(number_words_tens),"|".join(number_words)))
main_rx = re.compile(r'\s*\d+(?:\s+(?:and\s+)?\d+){2,}')
numbers_1_99 = number_words
numbers_1_99.extend(tens if ones == "zero" else (tens + "-" + ones) # stackoverflow.com/a/8982279/3832970
    for tens in "twenty thirty forty fifty sixty seventy eighty ninety".split()
    for ones in numbers_1_99[0:10])

def text2int(textnum, numwords={}): # stackoverflow.com/a/493788/3832970
    units = [
        "zero", "one", "two", "three", "four", "five", "six", "seven", "eight",
        "nine", "ten", "eleven", "twelve", "thirteen", "fourteen", "fifteen",
        "sixteen", "seventeen", "eighteen", "nineteen",
    ]
    tens = ["", "", "twenty", "thirty", "forty", "fifty", "sixty", "seventy", "eighty", "ninety"]
    numwords["and"] = (1, 0)
    for idx, word in enumerate(units):
        numwords[word] = (1, idx)
    for idx, word in enumerate(tens):
        numwords[word] = (1, idx * 10)
    current = result = 0
    for word in textnum.split():
        if word not in numwords:
          raise Exception("Illegal word: " + word)

        scale, increment = numwords[word]
        current = current + increment

    return result + current
sample1 = "hello my name is sofie my social security number is thirteen zero four five and seventy eighteen seven and forty and I live on mountain street number twelve"
sample1 = number_words_rx.sub(lambda x: str(text2int(x.group())), sample1)
re_results = main_rx.sub('', sample1)
print( re.sub(r'\d{1,2}', lambda x: numbers_1_99[int(x.group())], re_results) )

Вывод: hello my name is sofie my social security number is and I live on mountain street number twelve

...