Разделить текстовый файл на границе предложения - PullRequest
3 голосов
/ 11 апреля 2011

Я должен обработать текстовый файл (электронная книга).Я хотел бы обработать его так, чтобы в каждой строке было одно предложение («файл, разделенный символом новой строки», да?).Как бы я справился с этой задачей, используя sed утилиту UNIX?Имеет ли он символ «граница предложения», как символ «границы слова» (я думаю, что версия GNU имеет это).Обратите внимание, что предложение может заканчиваться точкой, многоточием, вопросом или восклицательным знаком, последние два в комбинации (например,?,!,!?, !!!!! все являются действительными «терминаторами предложения»).Входной файл отформатирован таким образом, что некоторые предложения содержат символы новой строки, которые необходимо удалить.

Я подумал о сценарии, подобном s/...|. |[!?]+ |/\n/g (не экранирован для лучшего чтения).Но он не удаляет переводы строк внутри предложений.

Как насчет C #?Было бы замечательно быстрее, если бы я использовал регулярные выражения как в sed?(Думаю, нет).Есть ли другой способ быстрее?

В любом случае (sed или C #) хорошо.Спасибо.

Ответы [ 5 ]

3 голосов
/ 19 октября 2013

Regex - это хороший вариант, который я использовал долгое время.

Очень хорошее регулярное выражение, которое отлично сработало для меня:

 string[] sentences = Regex.Split(sentence, @"(?<=['""A-Za-z0-9][\.\!\?])\s+(?=[A-Z])");

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

Например, если мой текст,

U.S.A. это замечательная нация. Большинство людей чувствуют себя счастливыми, живя там.

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

Это то, что заставило меня искать технику машинного обучения, и, наконец, SharpNLP отлично сработал для меня.

 private string mModelPath = @"C:\Users\ATS\Documents\Visual Studio 2012\Projects\Google_page_speed_json\Google_page_speed_json\bin\Release\";
 private OpenNLP.Tools.SentenceDetect.MaximumEntropySentenceDetector mSentenceDetector;
 private string[] SplitSentences(string paragraph)
    {
        if (mSentenceDetector == null)
        {
            mSentenceDetector = new OpenNLP.Tools.SentenceDetect.EnglishMaximumEntropySentenceDetector(mModelPath + "EnglishSD.nbin");
        }

        return mSentenceDetector.SentenceDetect(paragraph);
    }

Здесь, в этом примере, я использовал SharpNLP, в котором я использовал EnglishSD.nbin - предварительно обученную модель для определения предложения.

Теперь, если я применю один и тот же вход к этому методу, он отлично разделит текст на два логических предложения.

Вы даже можете использовать токены, POSTag, Chuck и т. Д., Используя проект SharpNLP.

Для пошаговой интеграции SharpNLP в ваше приложение C # прочитайте подробную статью, которую я написал. Она объяснит вам интеграцию с фрагментами кода.

Спасибо

1 голос
/ 11 апреля 2011

Разделение предложений - нетривиальная задача, для которой были разработаны алгоритмы машинного обучения. Но разделение пробела между [.\?!]+ и заглавной буквой [A-Z] может быть хорошей эвристикой. Удалите символы новой строки сначала с помощью tr, затем примените RE:

tr '\r\n' ' ' | sed 's/\([.?!]\)\s\s*\([A-Z]\)/\1\n\2/g'

Вывод должен состоять из одного предложения в строке. Проверьте вывод и уточните RE, если найдете ошибки. (Например, mr. Ed будет обрабатываться неправильно. Может быть, составить список таких сокращений.)

Скорость C # или sed может быть определена только экспериментально.

0 голосов
/ 19 апреля 2011

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

Похоже, вы в первую очередь интересуетесь английским языком, поэтому уже представленная эвристика регулярных выражений может соответствовать вашим потребностям. Если вам нужно более точное решение (за счет чуть большей сложности), вы можете рассмотреть возможность использования LingPipe, платформы NLP с открытым исходным кодом. Мне очень повезло с LingPipe, несколько раз я его использовал.

См. http://alias -i.com / lingpipe / demos / tutorial / предложений / read-me.html для получения подробного руководства по сегментации предложений.

0 голосов
/ 12 апреля 2011

Вы можете проверить мой учебник http://code.google.com/p/graph-expression/wiki/SentenceSplitting Основная идея состоит в том, чтобы иметь разделенные символы и невозможное условие до / после каждого разделения. Простая эвристика работает очень хорошо.

0 голосов
/ 11 апреля 2011

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

var sentences = Regex.Matches(input, @"[\w ,]+[\.!?]+")
foreach (Match match in sentences)
{
  Console.WriteLine(match.Value);
}

Это должно соответствовать предложениям, содержащим слова, пробелы и запятые и заканчивающиеся (любым числом) точками, восклицательными и вопросительными знаками.

...