Сегментация предложений с использованием регулярных выражений

У меня есть несколько текстовых (SMS) сообщений, и я хочу сегментировать их, используя точку ('.') в качестве разделителя. Я не могу обрабатывать следующие типы сообщений. Как я могу сегментировать эти сообщения, используя Regex в Python.

Перед сегментацией:

'hyper count 16.8mmol/l.plz review b4 5pm.just to inform u.thank u'
'no of beds 8.please inform person in-charge.tq'

После сегментации:

'hyper count 16.8mmol/l' 'plz review b4 5pm' 'just to inform u' 'thank u'
'no of beds 8' 'please inform person in-charge' 'tq'

Каждая строка представляет собой отдельное сообщение

Обновлено:

Я занимаюсь обработкой естественного языка и считаю, что '16.8mmmol/l' и 'no of beds 8.2 cups of tea.' можно рассматривать как одно и то же. Мне достаточно точности 80%, но я хочу максимально уменьшить False Positive.


person Maggie    schedule 19.07.2011    source источник
comment
Я думаю, что ваши предложения неправильные, поэтому регулярное выражение не является подходящим решением, если вы не предоставите все правила разделения.   -  person Kirill Polishchuk    schedule 19.07.2011
comment
Как вы различаете единицы (16,8) и предложения, которые заканчиваются и начинаются цифрами (количество кроватей 8,2 чашки чая)?   -  person Ikke    schedule 19.07.2011
comment
Я занимаюсь обработкой естественного языка и считаю, что 16.8mmmol/l и no of beds 8.2 cups of tea. можно рассматривать как одно и то же. Мне достаточно точности 80%, но я хочу максимально уменьшить количество ложных срабатываний.   -  person Maggie    schedule 19.07.2011
comment
Я полагаю, невозможно научить испытуемых, как правильно писать? Буквально на несколько мест хватит...   -  person carlpett    schedule 19.07.2011
comment
@polishchuk Но числа регулярны, и можно использовать регулярное выражение, чтобы избежать разделения из-за точек в числах, см. Мой ответ   -  person eyquem    schedule 20.07.2011
comment
@eyquem, вы предполагали, что предложение не может заканчиваться цифрой, а следующее начинается с цифры. Больше не надо. Это основное предположение.   -  person Kirill Polishchuk    schedule 20.07.2011
comment
@polischuk Почему предположение? Это то, что Махин говорит в своем комментарии: он хочет рассматривать точку в no of beds 8.2 cups of tea как точку в 16.8mmmol/l , то есть точки, над которыми не нужно выполнять разбиение. Мое решение расширяет это исключение точек из категории точек разделителей на все точки, присутствующие в числе.   -  person eyquem    schedule 20.07.2011
comment
@polishchuk Дело в том, что считать числом. В ссылке, которую я дал в качестве источника моего регулярного выражения, определение чисел очень широкое (включая числа с запятыми, научные обозначения и т. д.). В следующем потоке определение, которое я взял, менее широкое: (stackoverflow.com/questions/5807952/)   -  person eyquem    schedule 20.07.2011
comment
@eyquem, ты меня убедил, +1   -  person Kirill Polishchuk    schedule 20.07.2011


Ответы (5)


Как насчет

re.split('(?<!\d)\.|\.(?!\d)', 'hyper count 16.8mmol/l.plz review b4 5pm.just to inform u.thank u')

Осмотры гарантируют, что ни с одной, ни с другой стороны нет цифры. Таким образом, это относится и к случаю 16.8. Это выражение не будет разбиваться, если с обеих сторон стоят цифры.

person stema    schedule 19.07.2011
comment
'(?<!\d)\.|\.(?!\d)' разделяет соответственно точки в beds 8.please и number .977 is . Это то, чего вы действительно хотите? Если нет, шаблон регулярного выражения должен быть '(?<!\d)\.(?!\d)' - person eyquem; 20.07.2011
comment
@eyquem да, это то, что я хотел и что я написал в своем объяснении. Вопрос в том, чего хочет ОП. - person stema; 20.07.2011
comment
Разве фраза either on one or the other side is not a digit не означает: слева от точки не должно быть цифр И справа от точки не должно быть цифр? Я не англоязычный и иногда неправильно понимаю английский. - person eyquem; 20.07.2011
comment
@eyquem нет, это значит ИЛИ. Я принимаю цифру с одной стороны точки, но не с обеих сторон. - person stema; 20.07.2011
comment
Ты прав. Я не знаю, почему я понимаю И, где вы написали ИЛИ .... ! Я должен был написать: не должно быть цифр слева И справа ВМЕСТЕ вокруг точки как значение either on one or the other side is not a digit. Но я думаю, было бы понятнее и точнее, если бы вы написали: либо с одной, либо с другой стороны нецифра - person eyquem; 20.07.2011

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

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

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

import re

regx = re.compile('(?<![\d.])(?!\.\.)'
                  '(?<![\d.][eE][+-])(?<![\d.][eE])(?<!\d[.,])'
                  '' #---------------------------------
                  '([+-]?)'
                  '(?![\d,]*?\.[\d,]*?\.[\d,]*?)'
                  '(?:0|,(?=0)|(?<!\d),)*'
                  '(?:'
                  '((?:\d(?!\.[1-9])|,(?=\d))+)[.,]?'
                  '|\.(0)'
                  '|((?<!\.)\.\d+?)'
                  '|([\d,]+\.\d+?))'
                  '0*'
                  '' #---------------------------------
                  '(?:'
                  '([eE][+-]?)(?:0|,(?=0))*'
                  '(?:'
                  '(?!0+(?=\D|\Z))((?:\d(?!\.[1-9])|,(?=\d))+)[.,]?'
                  '|((?<!\.)\.(?!0+(?=\D|\Z))\d+?)'
                  '|([\d,]+\.(?!0+(?=\D|\Z))\d+?))'
                  '0*'
                  ')?'
                  '' #---------------------------------
                  '(?![.,]?\d)')



simpler_regex = re.compile('(?<![\d.])0*(?:'
                           '(\d+)\.?|\.(0)'
                           '|(\.\d+?)|(\d+\.\d+?)'
                           ')0*(?![\d.])')


def split_outnumb(string, regx=regx, a=0):
    excluded_pos = [x for mat in regx.finditer(string) for x in range(*mat.span()) if string[x]=='.']
    li = []
    for xdot in (x for x,c in enumerate(string) if c=='.' and x not in excluded_pos):
        li.append(string[a:xdot])
        a = xdot + 1
    li.append(string[a:])
    return li





for sentence in ('hyper count 16.8mmol/l.plz review b4 5pm.just to inform u.thank u',
                 'no of beds 8.please inform person in-charge.tq',
                 'no of beds 8.2 cups of tea.tarabada',
                 'this number .977 is a float',
                 'numbers 214.21E+45 , 478945.E-201 and .12478E+02 are in scientific.notation',
                 'an indian number 12,45,782.258 in this.sentence and 45,78,325. is another',
                 'no dot in this sentence',
                 ''):
    print 'sentence         =',sentence
    print 'splitted eyquem  =',split_outnumb(sentence)
    print 'splitted eyqu 2  =',split_outnumb(sentence,regx=simpler_regex)
    print 'splitted gurney  =',re.split(r"\.(?!\d)", sentence)
    print 'splitted stema   =',re.split('(?<!\d)\.|\.(?!\d)',sentence)
    print

результат

sentence         = hyper count 16.8mmol/l.plz review b4 5pm.just to inform u.thank u
splitted eyquem  = ['hyper count 16.8mmol/l', 'plz review b4 5pm', 'just to inform u', 'thank u']
splitted eyqu 2  = ['hyper count 16.8mmol/l', 'plz review b4 5pm', 'just to inform u', 'thank u']
splitted gurney  = ['hyper count 16.8mmol/l', 'plz review b4 5pm', 'just to inform u', 'thank u']
splitted stema   = ['hyper count 16.8mmol/l', 'plz review b4 5pm', 'just to inform u', 'thank u']

sentence         = no of beds 8.please inform person in-charge.tq
splitted eyquem  = ['no of beds 8.please inform person in-charge', 'tq']
splitted eyqu 2  = ['no of beds 8.please inform person in-charge', 'tq']
splitted gurney  = ['no of beds 8', 'please inform person in-charge', 'tq']
splitted stema   = ['no of beds 8', 'please inform person in-charge', 'tq']

sentence         = no of beds 8.2 cups of tea.tarabada
splitted eyquem  = ['no of beds 8.2 cups of tea', 'tarabada']
splitted eyqu 2  = ['no of beds 8.2 cups of tea', 'tarabada']
splitted gurney  = ['no of beds 8.2 cups of tea', 'tarabada']
splitted stema   = ['no of beds 8.2 cups of tea', 'tarabada']

sentence         = this number .977 is a float
splitted eyquem  = ['this number .977 is a float']
splitted eyqu 2  = ['this number .977 is a float']
splitted gurney  = ['this number .977 is a float']
splitted stema   = ['this number ', '977 is a float']

sentence         = numbers 214.21E+45 , 478945.E-201 and .12478E+02 are in scientific.notation
splitted eyquem  = ['numbers 214.21E+45 , 478945.E-201 and .12478E+02 are in scientific', 'notation']
splitted eyqu 2  = ['numbers 214.21E+45 , 478945.E-201 and .12478E+02 are in scientific', 'notation']
splitted gurney  = ['numbers 214.21E+45 , 478945', 'E-201 and .12478E+02 are in scientific', 'notation']
splitted stema   = ['numbers 214.21E+45 , 478945', 'E-201 and ', '12478E+02 are in scientific', 'notation']

sentence         = an indian number 12,45,782.258 in this.sentence and 45,78,325. is another
splitted eyquem  = ['an indian number 12,45,782.258 in this', 'sentence and 45,78,325. is another']
splitted eyqu 2  = ['an indian number 12,45,782.258 in this', 'sentence and 45,78,325. is another']
splitted gurney  = ['an indian number 12,45,782.258 in this', 'sentence and 45,78,325', ' is another']
splitted stema   = ['an indian number 12,45,782.258 in this', 'sentence and 45,78,325', ' is another']

sentence         = no dot in this sentence
splitted eyquem  = ['no dot in this sentence']
splitted eyqu 2  = ['no dot in this sentence']
splitted gurney  = ['no dot in this sentence']
splitted stema   = ['no dot in this sentence']

sentence         = 
splitted eyquem  = ['']
splitted eyqu 2  = ['']
splitted gurney  = ['']
splitted stema   = ['']

РЕДАКТИРОВАТЬ 1

Я добавил simpler_regex, определяющий числа, из моего поста в эта тема

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

person eyquem    schedule 20.07.2011
comment
+1 за сравнение различных решений. Очень хорошо. - person stema; 20.07.2011

вы можете использовать отрицательное предварительное утверждение для соответствия "." без цифры, и используйте re.split для этого:

>>> import re
>>> splitter = r"\.(?!\d)"
>>> s = 'hyper count 16.8mmol/l.plz review b4 5pm.just to inform u.thank u'
>>> re.split(splitter, s)
['hyper count 16.8mmol/l', 'plz review b4 5pm', 'just to inform u', 'thank u']
>>> s = 'no of beds 8.please inform person in-charge.tq'
>>> re.split(splitter, s)
['no of beds 8', 'please inform person in-charge', 'tq']
person gurney alex    schedule 19.07.2011

Это зависит от вашего точного предложения, но вы можете попробовать:

.*?[a-zA-Z0-9]\.(?!\d)

Посмотрите, работает ли это. Это останется в кавычках, но при необходимости вы можете удалить их.

person Francis Gilbert    schedule 19.07.2011

"...".split(".")

split — это встроенная функция Python, которая разделяет строку по определенному символу.

person Katriel    schedule 19.07.2011
comment
Это разделило бы . в 16,8ммоль/л тоже. - person Ikke; 19.07.2011