Как подсчитать количество абзацев в строке на С#

Я пытаюсь подсчитать количество абзацев в строке на С#.

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

This is a paragraph.

This
is
a
paragraph.



This is a paragraph.

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

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


person user3651656    schedule 02.06.2014    source источник
comment
Регулярные выражения могут быть способом сделать это, например /[\r\n][\r\n]+/   -  person Iłya Bursov    schedule 02.06.2014
comment
@Lashane Это позволяет \r\n закончить абзац.   -  person    schedule 02.06.2014
comment
Как определить конец абзаца? Это любая серия из более чем одной пары CRLF? Должен ли быть символ ., за которым следует пустая строка или конец файла? Является ли строка пустой, если она содержит только пробелы? Каждый вариант - это другое регулярное выражение: P   -  person Corey    schedule 02.06.2014


Ответы (3)


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

Regex.Matches(s, "[^\r\n]+((\r|\n|\r\n)[^\r\n]+)*")

[^\r\n]+ означает ненулевое количество символов, отличных от новой строки. \r|\n|\r\n — это различные формы новой строки. И в основном для абзаца вам нужно, чтобы они чередовались.

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

Чтобы рассматривать пустые строки как пустые строки, вы можете изменить определение «строки» с «ненулевое количество символов, отличных от новой строки», на «любое количество символов, отличных от новой строки, за которыми следует непустой символ, за которым следует любой количество символов, отличных от новой строки". Для простоты единственный символ, который я посчитал пустым, который не может быть частью разрыва строки, — это пробел, но вы можете включить и другие символы (например, табуляцию).

Regex.Matches(s, "[^\r\n]*[^ \r\n]+[^\r\n]*((\r|\n|\r\n)[^\r\n]*[^ \r\n]+[^\r\n]*)*")

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

person Community    schedule 02.06.2014
comment
@user3651656 Regex.Matches(ttes, "[^\r\n]+((\r|\n|\r\n)[^\r\n]+)*").Count должен считать - person brainless coder; 02.06.2014
comment
Спасибо. Просто из любопытства, есть ли способ заставить его обрабатывать строки, содержащие только пробельные символы, так же, как пустые строки? - person user3651656; 02.06.2014
comment
@user3651656 user3651656 Это должно быть возможно, но если это уже трудно читать, то станет намного хуже. Отредактирую, когда у меня будет возможность протестировать снова. - person ; 02.06.2014
comment
@ user3651656 Обновлено. - person ; 02.06.2014

Если вы готовы избегать регулярных выражений, то это работает:

var paragraphs =
    text
        .Split(
            new [] { Environment.NewLine + Environment.NewLine },
            StringSplitOptions.RemoveEmptyEntries)
        .Count();
person Enigmativity    schedule 02.06.2014
comment
Это умно! Вы правы, когда вы хотите только подсчитать количество абзацев, не имеет значения, что вы иногда включаете фиктивный символ новой строки в абзац. - person ; 02.06.2014
comment
@hvd - И, честно говоря, я считаю, что регулярное выражение просто затрудняет понимание. Конечно, регулярное выражение эффективно для компьютера, но для людей оно просто отстой. - person Enigmativity; 02.06.2014
comment
На самом деле в вашем ответе отсутствует один случай: он не обрабатывает завершающее нечетное количество новых строк: он возвращает два для "a" + Environment.NewLine + Environment.NewLine + Environment.NewLine. - person ; 02.06.2014
comment
Да, я согласен с тем, что регулярные выражения трудно читать, но в первую очередь я сосредоточился на правильности, а уж потом на удобочитаемости. Другими словами, я выбрал самый читаемый способ, который только мог придумать, чтобы получить правильный ответ. Я не рассматривал ваш подход, я не думал об этом, но я мог бы также опубликовать его как ответ, если бы имел. - person ; 02.06.2014
comment
Я не уверен, так ли отформатирована моя строка (она скопирована из содержимого RichEditBox в WinRT), но мне кажется, что это возвращает 1 независимо от того, что находится внутри строки. Есть ли способ исправить это? - person user3651656; 02.06.2014
comment
@user3651656 user3651656 В этом ответе предполагается, что все символы новой строки равны Environment.NewLine ("\r\n" в Windows). Возможно, используемый вами элемент управления использует вместо этого "\n". - person ; 02.06.2014

Вы можете попробовать следующее:

MultiParagraphString.Split(new [] {Environment.NewLine}, 
           StringSplitOptions.RemoveEmptyEntries);

Это вернет IEnumerable. Если вы хотите преобразовать их в свои структуры, просто используйте Select:

MultiParagraphString.Split(new [] {Environment.NewLine}, 
           StringSplitOptions.RemoveEmptyEntries)
          .Select(s => new ParagraphInfo(s)).ToList();

Скопировано из вопроса Как разделить абзацы в строке

person Mujassir Nasir    schedule 02.06.2014
comment
Вы проверили это? Это возвращает 6. - person Sriram Sakthivel; 02.06.2014
comment
Это возвращает каждую строку, а не каждый абзац. - person B.K.; 02.06.2014
comment
Я думаю, что это решение может потребовать некоторой модификации. - person Mujassir Nasir; 02.06.2014
comment
Какие модификации? Тогда это не ответ на заданный вопрос. - person Sriram Sakthivel; 02.06.2014