Здравствуйте. Вопрос про разделение текста на предложения. Да, что есть много похожих тем, но они все немного не те, если я пропустил на форуме тему с решением этого вопроса или это умеет делать надстройка PLEX или другие надстройки, то подскажите, пожалуйста, ссылку на ответ.
Более менее понятно, как бы с текстом, который начинается с заглавной буквы и кончается точкой, можно сделать разделение по точке, но вот что делать, когда в одном предложении несколько точек. Может быть, как то можно задать условие разделять предложение по "точке пробел и потом любая заглавная буква" (". А"). Или может есть более продуманное решение, например волнует, что после точки может стоять цифра, цифра может стоять как в предложении и так и после предложения.
Пример текста. Например он в колонке описание: "Функция 12345. Выводит в ячейку статическое случайное число в заданном диапазоне. От встроенной функции СЛУЧМЕЖДУ отличается тем, что эта функция не пересчитывается каждый раз вместе с остальными функциями листа при изменении любой ячейки, т.е. сохраняет свое первоначальное значение."
Разделить на колонки по количеству предложений.
Колонка 2: "Функция 12345" Колонка 3: "Выводит в ячейку статическое случайное число в заданном диапазоне" Колонка 4: "От встроенной функции СЛУЧМЕЖДУ отличается тем, что эта функция не пересчитывается каждый раз вместе с остальными функциями листа при изменении любой ячейки, т.е. сохраняет свое первоначальное значение"
Здравствуйте. Вопрос про разделение текста на предложения. Да, что есть много похожих тем, но они все немного не те, если я пропустил на форуме тему с решением этого вопроса или это умеет делать надстройка PLEX или другие надстройки, то подскажите, пожалуйста, ссылку на ответ.
Более менее понятно, как бы с текстом, который начинается с заглавной буквы и кончается точкой, можно сделать разделение по точке, но вот что делать, когда в одном предложении несколько точек. Может быть, как то можно задать условие разделять предложение по "точке пробел и потом любая заглавная буква" (". А"). Или может есть более продуманное решение, например волнует, что после точки может стоять цифра, цифра может стоять как в предложении и так и после предложения.
Пример текста. Например он в колонке описание: "Функция 12345. Выводит в ячейку статическое случайное число в заданном диапазоне. От встроенной функции СЛУЧМЕЖДУ отличается тем, что эта функция не пересчитывается каждый раз вместе с остальными функциями листа при изменении любой ячейки, т.е. сохраняет свое первоначальное значение."
Разделить на колонки по количеству предложений.
Колонка 2: "Функция 12345" Колонка 3: "Выводит в ячейку статическое случайное число в заданном диапазоне" Колонка 4: "От встроенной функции СЛУЧМЕЖДУ отличается тем, что эта функция не пересчитывается каждый раз вместе с остальными функциями листа при изменении любой ячейки, т.е. сохраняет свое первоначальное значение"atatat111
Можно начать решение задачи, например, с помощью простейшей пользовательской функции (UDF): [vba]
Код
Function splitTo3parts(ByVal strSource) splitTo3parts = Split(Replace(strSource, ". ", ".~", , 2), "~") End Function
[/vba]И дальше вводим формулу массива с этой UDF в три соседние ячейки одной строки. Например, исходная строка в ячейке A2. Тогда выделяем диапазон B2:D2, вводим формулу:
Код
=splitTo3parts(A2)
и жмём Ctrl+Shift+Enter. При протягивании вниз также сначала выделяем эти три "неделимые" ячейки и тянем все три за правый нижний угол ячейки D2.
Когда все ячейки с формулами рассчитаются, наверное, имеет смысл превратить их в "только значения" специальной вставкой.
Почему выше я написал "НАЧАТЬ решение задачи"? Потому, что, скорее всего, в некоторых случаях возникнут еще какие-то нюансы, которые придется либо разбирать вручную, либо сочинять еще какой-то алгоритм, предварительно исключив из рассмотрения те строки, в которых результаты первичной обработки с помощью UDF уже устраивают.
Можно начать решение задачи, например, с помощью простейшей пользовательской функции (UDF): [vba]
Код
Function splitTo3parts(ByVal strSource) splitTo3parts = Split(Replace(strSource, ". ", ".~", , 2), "~") End Function
[/vba]И дальше вводим формулу массива с этой UDF в три соседние ячейки одной строки. Например, исходная строка в ячейке A2. Тогда выделяем диапазон B2:D2, вводим формулу:
Код
=splitTo3parts(A2)
и жмём Ctrl+Shift+Enter. При протягивании вниз также сначала выделяем эти три "неделимые" ячейки и тянем все три за правый нижний угол ячейки D2.
Когда все ячейки с формулами рассчитаются, наверное, имеет смысл превратить их в "только значения" специальной вставкой.
Почему выше я написал "НАЧАТЬ решение задачи"? Потому, что, скорее всего, в некоторых случаях возникнут еще какие-то нюансы, которые придется либо разбирать вручную, либо сочинять еще какой-то алгоритм, предварительно исключив из рассмотрения те строки, в которых результаты первичной обработки с помощью UDF уже устраивают.Gustav
Gustav, китин, Благодарю за ответы! Я прошу прощения, я не совсем точно написал. Таких строк с текстом может быть например ~100, в каждой строке текст, в котором разное количество предложений (в которых могут быть знаки "!,?" любые короче), от одного предложения и до бесконечности, ну точнее наверное не больше ~30-40 предложений.
Gustav, Посмотрев вашу формулу, пришла мысль, а можно ли указать такое условие? Например когда строчные буквы после точки ". абвгдеёжз...эюя" - не делать разделения предложения, а когда заглавная буква после точки делать разделение ". АБВГДЕЁЖЗ...ЭЮЯ".
китин, Ваш вариант работает просто идеально, но только для текстового примера, а если вставить другой текст с другими количеством предложений и знаками, к сожалению, как я понял перестает работать.
Gustav, китин, Благодарю за ответы! Я прошу прощения, я не совсем точно написал. Таких строк с текстом может быть например ~100, в каждой строке текст, в котором разное количество предложений (в которых могут быть знаки "!,?" любые короче), от одного предложения и до бесконечности, ну точнее наверное не больше ~30-40 предложений.
Gustav, Посмотрев вашу формулу, пришла мысль, а можно ли указать такое условие? Например когда строчные буквы после точки ". абвгдеёжз...эюя" - не делать разделения предложения, а когда заглавная буква после точки делать разделение ". АБВГДЕЁЖЗ...ЭЮЯ".
китин, Ваш вариант работает просто идеально, но только для текстового примера, а если вставить другой текст с другими количеством предложений и знаками, к сожалению, как я понял перестает работать.atatat111
и "пример" поставил в кавычки, так как никакого примера у вас нетути и писал формулы только для утренней разминки мозгов. если хотите правильного решения, то приложите СВОЙ файл пример со всеми возможными вариантами.
и "пример" поставил в кавычки, так как никакого примера у вас нетути и писал формулы только для утренней разминки мозгов. если хотите правильного решения, то приложите СВОЙ файл пример со всеми возможными вариантами.китин
Не судите очень строго:я пытаюсь научиться ЯД 41001877306852
пришла мысль, а можно ли указать такое условие? Например когда строчные буквы после точки ". абвгдеёжз...эюя" - не делать разделения предложения, а когда заглавная буква после точки делать разделение ". АБВГДЕЁЖЗ...ЭЮЯ".
Можно. Правда, функция заметно усложнится. Новая ее версия - с использованием механизма регулярных выражений: [vba]
Код
Function splitTo3parts(ByVal strSource) Dim objRegExp As Object 'RegExp Dim colMatches As Object 'MatchCollection
If colMatches.Count > 0 Then Mid(strSource, colMatches(0).FirstIndex + 2) = "~" If colMatches.Count > 1 Then Mid(strSource, colMatches(1).FirstIndex + 2) = "~"
splitTo3parts = Split(strSource & String(2 - WorksheetFunction.Min(colMatches.Count, 2), "~"), "~", 3) End Function
[/vba] Заковыристая последняя строка функции нужна для того, чтобы всегда возвращать массив из трёх элементов. Если разделителей не найдено, то начальный элемент массива содержит всю исходную строку, а два других элемента - пустые строки. Если разделитель только один, то последний элемент массива будет также пустой строкой. Таким образом мы боремся с возможными ошибками типа "#H/Д" или значениями 0 при пустой исходной строке. Ну, а первый параметр функции повтора String не может быть отрицательным числом, поэтому применяем функцию Min.
пришла мысль, а можно ли указать такое условие? Например когда строчные буквы после точки ". абвгдеёжз...эюя" - не делать разделения предложения, а когда заглавная буква после точки делать разделение ". АБВГДЕЁЖЗ...ЭЮЯ".
Можно. Правда, функция заметно усложнится. Новая ее версия - с использованием механизма регулярных выражений: [vba]
Код
Function splitTo3parts(ByVal strSource) Dim objRegExp As Object 'RegExp Dim colMatches As Object 'MatchCollection
If colMatches.Count > 0 Then Mid(strSource, colMatches(0).FirstIndex + 2) = "~" If colMatches.Count > 1 Then Mid(strSource, colMatches(1).FirstIndex + 2) = "~"
splitTo3parts = Split(strSource & String(2 - WorksheetFunction.Min(colMatches.Count, 2), "~"), "~", 3) End Function
[/vba] Заковыристая последняя строка функции нужна для того, чтобы всегда возвращать массив из трёх элементов. Если разделителей не найдено, то начальный элемент массива содержит всю исходную строку, а два других элемента - пустые строки. Если разделитель только один, то последний элемент массива будет также пустой строкой. Таким образом мы боремся с возможными ошибками типа "#H/Д" или значениями 0 при пустой исходной строке. Ну, а первый параметр функции повтора String не может быть отрицательным числом, поэтому применяем функцию Min.Gustav
Таких строк с текстом может быть например ~100, в каждой строке текст, в котором разное количество предложений (в которых могут быть знаки "!,?" любые короче)
у меня так получилось: [vba]
Код
Function Split_by_sentence(ByVal StringInp As String, Optional ByVal Patt As String = "([\.|\?|\!]+\s+[A-ZÀ-ß])") Dim i&, arr() As String With CreateObject("Vbscript.regexp") .Pattern = Patt .Global = True If Not .test(StringInp) Then ReDim arr(0) arr(0) = StringInp Else Set Matches = .Execute(StringInp) ReDim arr(Matches.Count) For i = 0 To Matches.Count - 1 If i = 0 Then arr(i) = Left(StringInp, Matches(i).FirstIndex + Len(Matches(i).submatches(0)) - 1) Else arr(i) = Mid(StringInp, Matches(i - 1).FirstIndex + Matches(i - 1).Length - 1, Matches(i).FirstIndex - Matches(i - 1).FirstIndex - Matches(i - 1).Length + Matches(i).Length) End If arr(i) = Trim(arr(i)) Next arr(i) = Mid(StringInp, Matches(i - 1).FirstIndex + Matches(i - 1).Length - 1, 999) arr(i) = Trim(arr(i)) End If End With
If Application.Caller.Cells.Count > UBound(arr) + 1 Then ReDim Preserve arr(Application.Caller.Cells.Count) Split_by_sentence = arr End Function
Таких строк с текстом может быть например ~100, в каждой строке текст, в котором разное количество предложений (в которых могут быть знаки "!,?" любые короче)
у меня так получилось: [vba]
Код
Function Split_by_sentence(ByVal StringInp As String, Optional ByVal Patt As String = "([\.|\?|\!]+\s+[A-ZÀ-ß])") Dim i&, arr() As String With CreateObject("Vbscript.regexp") .Pattern = Patt .Global = True If Not .test(StringInp) Then ReDim arr(0) arr(0) = StringInp Else Set Matches = .Execute(StringInp) ReDim arr(Matches.Count) For i = 0 To Matches.Count - 1 If i = 0 Then arr(i) = Left(StringInp, Matches(i).FirstIndex + Len(Matches(i).submatches(0)) - 1) Else arr(i) = Mid(StringInp, Matches(i - 1).FirstIndex + Matches(i - 1).Length - 1, Matches(i).FirstIndex - Matches(i - 1).FirstIndex - Matches(i - 1).Length + Matches(i).Length) End If arr(i) = Trim(arr(i)) Next arr(i) = Mid(StringInp, Matches(i - 1).FirstIndex + Matches(i - 1).Length - 1, 999) arr(i) = Trim(arr(i)) End If End With
If Application.Caller.Cells.Count > UBound(arr) + 1 Then ReDim Preserve arr(Application.Caller.Cells.Count) Split_by_sentence = arr End Function
Gustav, SLAVICK, может и учли, если так, то хорошо, я код не изучал и в регулярках слаб, но после точки(? ! могут быть излишества всякие, типа перевода строк и возвратов корретки, как до пробела, так и после нескольких.
Gustav, SLAVICK, может и учли, если так, то хорошо, я код не изучал и в регулярках слаб, но после точки(? ! могут быть излишества всякие, типа перевода строк и возвратов корретки, как до пробела, так и после нескольких.bmv98rus
Замечательный Временно просто медведь , процентов на 20.
Gustav, SLAVICK, Последняя версия работает идеально! Вставил для примера текст с этого форму из этой темы http://www.excelworld.ru/forum/13-5074-51887-16-1372997684. Там написан так текст, что в конце предложения нет точки, но есть перенос строки, можно ли ещё указать в этом выражении, перенос строки как окончание предложения, чтобы точно так же, как предложение сточкой, вы водил в столбец? В таблице пометил где переносы строк словом "ЗДЕСЬ".
Gustav, SLAVICK, Последняя версия работает идеально! Вставил для примера текст с этого форму из этой темы http://www.excelworld.ru/forum/13-5074-51887-16-1372997684. Там написан так текст, что в конце предложения нет точки, но есть перенос строки, можно ли ещё указать в этом выражении, перенос строки как окончание предложения, чтобы точно так же, как предложение сточкой, вы водил в столбец? В таблице пометил где переносы строк словом "ЗДЕСЬ".atatat111
SLAVICK, Спасибо распознает предложения отлично! А можно добавить в выражение исключения, когда не нужно разделять предложение? Например "пробел-точка-г" - " .г" г. - это город. Это как бы только один пример, остальные исключения я сам вставлю в выражение.
SLAVICK, Спасибо распознает предложения отлично! А можно добавить в выражение исключения, когда не нужно разделять предложение? Например "пробел-точка-г" - " .г" г. - это город. Это как бы только один пример, остальные исключения я сам вставлю в выражение.atatat111
Реплэйсом его, реплэйсом - к обычному. Вообще, считаю, что это всё - забота топикстартера, а именно - подать функции текст, предварительно очищенный от подобных "нюансов". Сказано в ТЗ "точка-пробел-Заглавная" - вот и получите-распишитесь! Или - новое ТЗ по результатам обсуждения.
Кстати, "\s" учитывает не только собственно пробел, но и другие пробельные символы типа табуляции и перевода строки (неразрывной - нет).
Реплэйсом его, реплэйсом - к обычному. Вообще, считаю, что это всё - забота топикстартера, а именно - подать функции текст, предварительно очищенный от подобных "нюансов". Сказано в ТЗ "точка-пробел-Заглавная" - вот и получите-распишитесь! Или - новое ТЗ по результатам обсуждения.
Кстати, "\s" учитывает не только собственно пробел, но и другие пробельные символы типа табуляции и перевода строки (неразрывной - нет).Gustav
Gustav, с одной стороны согласен, а с другой, ТС понятия может не иметь о существовании таких подводных камней.
Попробовал воспользоваться встроенными средствами Word [vba]
Код
Selection.MoveRight Unit:=wdSentence, Count:=1
[/vba] Не справился он с примером.:-) на этом осекся - знаки "!,?" . естесвенно "Маша вышла, т.е. Маша ушла." стало двумя предложениями. И даже это "Мама вышла, т.е. мама ушла." тоже.
Gustav, с одной стороны согласен, а с другой, ТС понятия может не иметь о существовании таких подводных камней.
Попробовал воспользоваться встроенными средствами Word [vba]
Код
Selection.MoveRight Unit:=wdSentence, Count:=1
[/vba] Не справился он с примером.:-) на этом осекся - знаки "!,?" . естесвенно "Маша вышла, т.е. Маша ушла." стало двумя предложениями. И даже это "Мама вышла, т.е. мама ушла." тоже.bmv98rus
Замечательный Временно просто медведь , процентов на 20.
Ну вот, вроде, учёл все высказанные пожелания, а также представляю, если что, куда надо будет вставить следующие хотелки.
[vba]
Код
Function splitTo3parts(ByVal strSource) Dim objRegExp As Object 'RegExp Dim colMatches As Object 'MatchCollection Dim sep As String
sep = vbTab
Set objRegExp = CreateObject("VBScript.RegExp") objRegExp.Global = True
'перенос строки как окончание предложения, чтобы точно так же, как предложение с точкой objRegExp.Pattern = "[^.?!]" & vbLf 'случай Alt+Enter в ячейке strSource = replaceEOL(objRegExp, strSource)
'а также неразрывного пробела - символа с кодом 160 strSource = Replace(strSource, Chr(160), " ")
'дополнительно чистим ПЕЧСИМВ (вдруг что-то еще осталось) 'и удаляем лишние пробелы With WorksheetFunction strSource = .Clean(strSource) strSource = .Trim(strSource) 'именно Trim табличной функцией End With 'здесь между символами остался максимум ОДИН пробел
'временно заменяем исключения - типа города г. и т.е., чтобы не мешались точками 'а также сюда добавим другие, если еще найдутся strSource = Replace(strSource, " г. ", " г_| ", , , vbBinaryCompare) 'заменяем только строчную "г." strSource = Replace(strSource, " т.е. ", " т_|е_| ")
objRegExp.Pattern = "[.?!]\s[A-ZА-Я0-9""]" 'добавил возможность начала предложения с цифры и двойной кавычки
Set colMatches = objRegExp.Execute(strSource)
If colMatches.Count > 0 Then Mid(strSource, colMatches(0).FirstIndex + 2) = sep If colMatches.Count > 1 Then Mid(strSource, colMatches(1).FirstIndex + 2) = sep
'восстанавливаем исключения - типа города и т.е. strSource = Replace(strSource, "г_|", "г.") strSource = Replace(strSource, "т_|е_|", "т.е.")
splitTo3parts = Split(strSource & String(2 - WorksheetFunction.Min(colMatches.Count, 2), sep), sep, 3) End Function
Function replaceEOL(objRegExp, strSource) Dim colMatches As Object 'MatchCollection Dim aMatch As Object 'Match
Set colMatches = objRegExp.Execute(strSource)
For Each aMatch In colMatches Mid(strSource, aMatch.FirstIndex + 2) = vbTab 'обязательно односимвольный разделитель Next
replaceEOL = Replace(strSource, vbTab, ". ") End Function
[/vba]
Ну вот, вроде, учёл все высказанные пожелания, а также представляю, если что, куда надо будет вставить следующие хотелки.
[vba]
Код
Function splitTo3parts(ByVal strSource) Dim objRegExp As Object 'RegExp Dim colMatches As Object 'MatchCollection Dim sep As String
sep = vbTab
Set objRegExp = CreateObject("VBScript.RegExp") objRegExp.Global = True
'перенос строки как окончание предложения, чтобы точно так же, как предложение с точкой objRegExp.Pattern = "[^.?!]" & vbLf 'случай Alt+Enter в ячейке strSource = replaceEOL(objRegExp, strSource)
'а также неразрывного пробела - символа с кодом 160 strSource = Replace(strSource, Chr(160), " ")
'дополнительно чистим ПЕЧСИМВ (вдруг что-то еще осталось) 'и удаляем лишние пробелы With WorksheetFunction strSource = .Clean(strSource) strSource = .Trim(strSource) 'именно Trim табличной функцией End With 'здесь между символами остался максимум ОДИН пробел
'временно заменяем исключения - типа города г. и т.е., чтобы не мешались точками 'а также сюда добавим другие, если еще найдутся strSource = Replace(strSource, " г. ", " г_| ", , , vbBinaryCompare) 'заменяем только строчную "г." strSource = Replace(strSource, " т.е. ", " т_|е_| ")
objRegExp.Pattern = "[.?!]\s[A-ZА-Я0-9""]" 'добавил возможность начала предложения с цифры и двойной кавычки
Set colMatches = objRegExp.Execute(strSource)
If colMatches.Count > 0 Then Mid(strSource, colMatches(0).FirstIndex + 2) = sep If colMatches.Count > 1 Then Mid(strSource, colMatches(1).FirstIndex + 2) = sep
'восстанавливаем исключения - типа города и т.е. strSource = Replace(strSource, "г_|", "г.") strSource = Replace(strSource, "т_|е_|", "т.е.")
splitTo3parts = Split(strSource & String(2 - WorksheetFunction.Min(colMatches.Count, 2), sep), sep, 3) End Function
Function replaceEOL(objRegExp, strSource) Dim colMatches As Object 'MatchCollection Dim aMatch As Object 'Match
Set colMatches = objRegExp.Execute(strSource)
For Each aMatch In colMatches Mid(strSource, aMatch.FirstIndex + 2) = vbTab 'обязательно односимвольный разделитель Next
replaceEOL = Replace(strSource, vbTab, ". ") End Function
Gustav, Благодарю! Один только вопрос, как изменить количество колонок, на которые делятся предложения? Сейчас на 3 колонки делятся, в остальных написано "Н/Д", попробовал сам изменить Ваше выражение, но не получилось.
Gustav, Благодарю! Один только вопрос, как изменить количество колонок, на которые делятся предложения? Сейчас на 3 колонки делятся, в остальных написано "Н/Д", попробовал сам изменить Ваше выражение, но не получилось.atatat111