регулярное выражение Python для получения чисел, расположенных в разных местах строки - PullRequest
2 голосов
/ 14 марта 2019

Это возможные варианты текста, который у меня есть,

4 bedrooms 2 bathrooms 3 carparks
3 bedroom house
Bedrooms 2, 
beds 5,
Bedrooms 1, 
2 bedrooms, 1 bathroom, 
Four bedrooms home, double garage
Four bedrooms home
Three double bedrooms home, garage
Three bedrooms home,
2 bedroom home unit with single carport.
Garage car spaces: 2, Bathrooms: 4, Bedrooms: 7,

Я пытаюсь определить количество спален в этом тексте. Мне удалось написать ниже,

  def get_bedroom_num(s):
    if ':' in s:
        out = re.search(r'(?:Bedrooms:|Bedroom:)(.*)', s,re.I).group(1)
    elif ',' in s:
        out = re.search(r'(?:bedrooms|bedroom|beds)(.*)', s,re.I).group(1)
    else:
        out = re.search(r'(.*)(?:bedrooms|bedroom).*', s,re.I).group(1)
    out = filter(lambda x: x.isdigit(), out)
    return out

Но это не захватывает все возможные случаи. Ключевым словом здесь является слово «спальня», текст всегда будет иметь текст «спальня» в передней или задней части номера. Есть ли лучший способ справиться с этим? Если не через регулярное выражение, может ли Named Entity Recognition в NLP?

Спасибо.

РЕДАКТИРОВАТЬ: -

Для случаев с 7 по 10 мне удалось преобразовать числа слов в целое, используя следующую функцию:

#Convert word to number
def text2int (textnum, numwords={}):
    if not numwords:
        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"]

        scales = ["hundred", "thousand", "million", "billion", "trillion"]

        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)
        for idx, word in enumerate(scales): numwords[word] = (10 ** (idx * 3 or 2), 0)

    ordinal_words = {'first':1, 'second':2, 'third':3, 'fifth':5, 'eighth':8, 'ninth':9, 'twelfth':12}
    ordinal_endings = [('ieth', 'y'), ('th', '')]

    textnum = textnum.replace('-', ' ')

    current = result = 0
    curstring = ""
    onnumber = False
    for word in textnum.split():
        if word in ordinal_words:
            scale, increment = (1, ordinal_words[word])
            current = current * scale + increment
            if scale > 100:
                result += current
                current = 0
            onnumber = True
        else:
            for ending, replacement in ordinal_endings:
                if word.endswith(ending):
                    word = "%s%s" % (word[:-len(ending)], replacement)

            if word not in numwords:
                if onnumber:
                    curstring += repr(result + current) + " "
                curstring += word + " "
                result = current = 0
                onnumber = False
            else:
                scale, increment = numwords[word]

                current = current * scale + increment
                if scale > 100:
                    result += current
                    current = 0
                onnumber = True

    if onnumber:
        curstring += repr(result + current)

    return curstring

так, с помощью этой функции «Дом с четырьмя спальнями, гараж на две машины» может быть преобразован в «Дом с четырьмя спальнями, гараж на две машины» перед выполнением любого регулярного выражения для получения номера.

1 Ответ

3 голосов
/ 14 марта 2019

Вы можете использовать следующее регулярное выражение, чтобы найти все различные комбинации и извлечь информацию о номере спальни,

(\w+\+?) *(?:double +)?bed(?:room)?s?|bed(?:room)?s?:? *(\d+\+?)

Чтобы точно перечислить только форму слова из числа, вы можете изменить (\w+) на \b(?:one|two|Three|Four|five|six|seven|eight|nine|ten|\d+)\b

Онлайн-демонстрация

Поскольку регулярное выражение имеет группы чередования, где захваченная информация может быть доступна либо в группе 1, либо в группе 2, этот код Python показывает, как выможет извлекать данные из соответствующим образом захваченной группы в регулярном выражении,

import re

def getRoomInfo(s):
 numRooms = re.search(r'(\w+\+?) *(?:double +)?bed(?:room)?s?|bed(?:room)?s?:? *(\d+\+?)', s, re.IGNORECASE)
 if (numRooms):
  if (numRooms.group(1) is not None):
   return numRooms.group(1)
  elif (numRooms.group(2) is not None):
   return numRooms.group(2)


arr = ['4 bedrooms 2 bathrooms 3 carparks','3 bedroom house','Bedrooms 2, ','beds 5,','Bedrooms 1, ','2 bedrooms, 1 bathroom, ','Four bedrooms home, double garage','Four bedrooms home','Three double bedrooms home, garage','Three bedrooms home,','2 bedroom home unit with single carport.','Garage car spaces: 2, Bathrooms: 4, Bedrooms: 7,\\\\', 'Three bedroom bungalow with conservatory and", "One bedroom unit","4+ bedroom(s), 2 bathroom(s), 2 garage(s)']

for s in arr:
 print(s, ' --> ', getRoomInfo(s))

Печатает следующее,

4 bedrooms 2 bathrooms 3 carparks  -->  4
3 bedroom house  -->  3
Bedrooms 2,   -->  2
beds 5,  -->  5
Bedrooms 1,   -->  1
2 bedrooms, 1 bathroom,   -->  2
Four bedrooms home, double garage  -->  Four
Four bedrooms home  -->  Four
Three double bedrooms home, garage  -->  Three
Three bedrooms home,  -->  Three
2 bedroom home unit with single carport.  -->  2
Garage car spaces: 2, Bathrooms: 4, Bedrooms: 7,\\  -->  7
Three bedroom bungalow with conservatory and", "One bedroom unit","4+ bedroom(s), 2 bathroom(s), 2 garage(s)  -->  Three

Edit2: еще одна версия кода Python, где он захватывает все совпадения встрока и возвращает результат в виде списка

import re

def getRoomInfoAll(s):
 matches = []
 pattern = re.compile(r'(\w+\+?) *(?:double +)?bed(?:room)?s?|bed(?:room)?s?:? *(\d+\+?)', re.IGNORECASE)
 for numRooms in pattern.finditer(s):
  if (numRooms.group(1) is not None and len(numRooms.group(1)) > 0):
   matches.append(numRooms.group(1))
  elif (numRooms.group(2) is not None and len(numRooms.group(2)) > 0):
   matches.append(numRooms.group(2))
 return matches


arr = ['4 bedrooms 2 bathrooms 3 carparks','3 bedroom house','Bedrooms 2, ','beds 5,','Bedrooms 1, ','2 bedrooms, 1 bathroom, ','Four bedrooms home, double garage','Four bedrooms home','Three double bedrooms home, garage','Three bedrooms home,','2 bedroom home unit with single carport.','Garage car spaces: 2, Bathrooms: 4, Bedrooms: 7,\\\\', 'Three bedroom bungalow with conservatory and", "One bedroom unit","4+ bedroom(s), 2 bathroom(s), 2 garage(s)']

for s in arr:
 print(s, ' --------> ', getRoomInfoAll(s))

Здесь выводятся все совпадения, найденные в строке.

4 bedrooms 2 bathrooms 3 carparks  -------->  ['4']
3 bedroom house  -------->  ['3']
Bedrooms 2,   -------->  ['2']
beds 5,  -------->  ['5']
Bedrooms 1,   -------->  ['1']
2 bedrooms, 1 bathroom,   -------->  ['2']
Four bedrooms home, double garage  -------->  ['Four']
Four bedrooms home  -------->  ['Four']
Three double bedrooms home, garage  -------->  ['Three']
Three bedrooms home,  -------->  ['Three']
2 bedroom home unit with single carport.  -------->  ['2']
Garage car spaces: 2, Bathrooms: 4, Bedrooms: 7,\\  -------->  ['7']
Three bedroom bungalow with conservatory and", "One bedroom unit","4+ bedroom(s), 2 bathroom(s), 2 garage(s)  -------->  ['Three', 'One', '4+']
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...