Разбивка текста на предложения и слова [дубликат]

126
18 апреля 2022, 16:20
На этот вопрос уже дан ответ здесь:
нерабочее решение через Linq c# (1 ответ)
Закрыт 1 год назад.

Задача с юлёрна
https://ulearn.me/course/basicprogramming/Praktika_Parser_predlozheniy__d41a27ad-a377-4fbd-ba1c-1bd761c69dd1

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

"предложения" отделены друг от друга одним из следующих символов .!?;:()

а "слова" могут состоять только из букв и символа апострофа ', отделены друг от друга любыми другими символами.

Метод должен возвращать список предложений, где каждое предложение — это список из одного или более слов в нижнем регистре List<List<string>>.
вот мое решение:

using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
namespace TextAnalysis
{
    static class SentencesParserTask
    {
        
        public static List<List<string>> ParseSentences(string text)
        {
            return SplitSentencesIntoWords(SplitIntoSentences(text));
        }
        
        public static string[] SplitIntoSentences(string text)
        {
            text = text.ToLower();
            char[] separators = {';','!','?','.',':','(',')'};
            string[] sentences = text.Split(separators).Where(x => x != string.Empty && x != null).ToArray();
        
            return sentences;    
        }
        public static List<List<string>> SplitSentencesIntoWords(string[] sentences)
        {
            var sentencesList = new List<List<string>>();
            
            foreach (string sentence in sentences)
            {
                var wordStartIndex = -1;
                List<string> words = new List<string>();
            
                for (int i = 0; i < sentence.Length;  i++)
                {
                    if (char.IsLetter(sentence[i]) || sentence[i].Equals('\'') )
                    {
                        if (wordStartIndex == -1)
                        {
                            wordStartIndex = i;
                            words.Add(sentence.Substring(wordStartIndex, 1));
                        }
                        else
                        {
                            words.Add(sentence.Substring(wordStartIndex+1, i - wordStartIndex));
                            wordStartIndex = -1;
                        }
                        
                    }
                    else
                    {
                        wordStartIndex = -1;
                    }
                }   
                if (words.Count > 0)
                {
                        var wordsArray = words.ToArray();
                        string result = string.Join("", wordsArray);
                        List<string> list = new List<string> {result};
                        sentencesList.Add(list);
                }
            }
            return sentencesList;        
        }       
    }
}   

при входной строке "abc" метод ParseSentences() должен возвращать {{"abc"}} (что он и делает в моем варианте)
при входной строке "b, c" метод ParseSentences() должен возвращать {{"b","c"}} (в моем варианте {{"bc"}})
как мне words добавлять нужно к sentencesList, чтобы метод для любого ввода работал верно?
помогите пожалуйста(

Answer 1
static readonly char[] seps = { ... }; // либо `HashSet<char>`
bool TrySeparateToSentences(string? input, out string[]?[]? sentences)
{
    sentences = null;
    if (string.IsNullOrEmpty(input)) return true;
    var sents = new List<List<string>>();
    for (var i = 0; i < input.Length; i++)
        if (char.IsWhiteSpace(input[i]))
            continue;
        else if (char.IsLetterOrDigit(input[i])) // использовать ваш метод определения символа слова
                                                 // (например, учитывать контрольные символы; тогда
                                                 // определяем категорию и по ней с помощью локальной
                                                 // функции, возвращающей `bool`, выполняем нижеуказанные
                                                 // инструкции)
        {
           if (sents.Count == 0) sents.Add(new List<string>());
            var start = i;
            while (i < input.Length && char.IsLetterOrDigit(input[i])) i++;
            var word = input.Substring(start, i - start);
            sents[^1].Add(word);
        }
        else if (seps.Contains(input[i]))
            sents.Add(new List<string>());
        else
            return false;
     if (sents.Count == 0) return true;
     sentences = new string[sents.Count][];
     for (var i = 0; i < sentences.Length; i++)
         sentences[i] = sents[i].Count == 0 ? null : sents[i].ToArray();
     return true;
}

Примечание. Реализация сделана без использования Span/ReadOnlySpan и Range для совместимости с .NET Framework.

Answer 2

нужно было просто рассмотреть ВСЕ возможные варианты событий
менять нужно было вот этот метод:

 public static List<List<string>> SplitSentencesIntoWords(string[] sentences)
        {
            var sentencesList = new List<List<string>>();
            
            foreach (string sentence in sentences)
            {
                var wordStartIndex = -1; var wordEndIndex = -1;
                List<string> words = new List<string>();
            
                for (int i = 0; i < sentence.Length;  i++)
                {
                    if (char.IsLetter(sentence[i]) || sentence[i].Equals('\'') )
                    {
                        if (wordStartIndex == -1)
                        {
                            wordStartIndex = i;
                        }
                        else
                        {
                            wordEndIndex = i;
                        }
                        if(i == sentence.Length - 1)
                        {
                           if(wordStartIndex != -1)
                           {
                               if(wordEndIndex != -1)
                               {
                                  words.Add(sentence.Substring(wordStartIndex, wordEndIndex-wordStartIndex+1));
                               }
                               else
                               {
                                  words.Add(sentence.Substring(wordStartIndex, 1));
                               }
                           }                    
                        }
                    }
                    else
                    {
                        if(wordStartIndex != -1)
                        {
                            if(wordEndIndex != -1)
                            {
                                words.Add(sentence.Substring(wordStartIndex, wordEndIndex-wordStartIndex+1));
                                wordEndIndex = -1;
                            }
                            else
                            {
                                words.Add(sentence.Substring(wordStartIndex, 1));
                            }
                            wordStartIndex = -1;
                        }               
                    }
                }   
                if (words.Count > 0)
                {
                        sentencesList.Add(words);  
                }
            }
            return sentencesList;        
        }       
    }
}   
READ ALSO
Строка подключение Entity для MSSQL на хостинге

Строка подключение Entity для MSSQL на хостинге

Доброе время суток, Взял хостинг goodhostkz, добавил проект и импортировал БД, но не как не могу настроить строку подключение

134
C# проверка входных параметров

C# проверка входных параметров

Не лишняя ли здесь проверка enum параметра? (UserRole - enum-объект)И вообще нужна ли проверка на enum типы во входных параметрах?! Спасибо за внимание!

170
Не могу запустить службу WCF ASP.NET

Не могу запустить службу WCF ASP.NET

Создал пустой apsnet проект

126
Создание транзакции FireBase с помощью Xamarin

Создание транзакции FireBase с помощью Xamarin

Необходимо просто поле count постоянно добавлять +1, как я понимаю если я сделаю так:

277