<commit_before>using System;
using System.Collections.Generic;
using System.Linq;

namespace XText
{
    public static class XTextParser
    {
        public static XTextElement Parse(string str)
        {
            str = str.Replace("\r\n", "\n");

            if (str.IndexOf("\n\n", StringComparison.Ordinal) != -1 || str.EndsWith("\n"))
            {
                var isLastAParagraph = str.EndsWith("\n");
                var paragraphs = str.TrimEnd('\n').Split(new[] { "\n\n" }, StringSplitOptions.None);
                var parsed = paragraphs.Select(ParseBlock).ToArray();
                for (var i = 0; i < parsed.Length; i++)
                {
                    var isLast = i == parsed.Length - 1;

                    if (isLast && !isLastAParagraph) continue;
                    if (parsed[i] is XInline) parsed[i] = new XParagraph((XInline) parsed[i]);
                }

                if (paragraphs.Length == 1)
                    return parsed.Single();
                return new XSection(parsed);
            }

            return ParseBlock(str);
        }

        private static XTextElement ParseBlock(string str)
        {
            if (str.StartsWith("  "))
            {
                return new XParagraph(BlockStyle.Indented, str.Substring(2));
            }

            return ParseInlineString(str);
        }

        private static XInline ParseInlineString(string str)
        {
            var inlines = new List<XInline>();
            bool formattedInlineMatch;
            do
            {
                formattedInlineMatch = false;
                const string boldDelimiter = "**";
                const string italicDelimiter = "*";
                var boldStart = str.IndexOf(boldDelimiter, StringComparison.Ordinal);
                var italicStart = str.IndexOf(italicDelimiter, StringComparison.Ordinal);
                var newLineStart = str.IndexOf("\n", StringComparison.Ordinal);

                // Fix escaped characters
                while (italicStart > 0 && str[italicStart - 1] == '\\')
                {
                    // Make sure backslash is not escaped
                    if (italicStart > 1 && str[italicStart - 2] == '\\')
                    {
                        // We are good to fix italicStart
                        var startIndex = italicStart + 1;
                        if (startIndex > str.Length)
                            break;
                        // Remove escape character for *
                        str = str.Remove(italicStart - 1, 1);
                        italicStart = str.IndexOf(italicDelimiter, startIndex, StringComparison.Ordinal);
                    }
                    else
                    {
                        str = str.Remove(italicStart - 1, 1);
                        italicStart = str.IndexOf(italicDelimiter, italicStart, StringComparison.Ordinal);
                        break;
                    }
                }

                if (newLineStart != -1 && 
                    (newLineStart < boldStart || boldStart == -1) &&
                    (newLineStart < italicStart || italicStart == -1))
                {
                    if (newLineStart == 0)
                    {
                        inlines.Add(new XLineBreak());
                        str = str.Substring(1);
                    }
                    else
                    {
                        inlines.Add(new XRun(str.Substring(0, newLineStart)));
                        str = str.Substring(newLineStart + 1);
                        inlines.Add(new XLineBreak());
                    }
                    formattedInlineMatch = true;
                }
                else if (boldStart != -1 && boldStart <= italicStart)
                {
                    str = ParseNextInline(str, boldDelimiter, boldStart, inlines, s => new XBold(s));
                    formattedInlineMatch = true;
                }
                else if (italicStart != -1)
                {
                    try
                    {
                        str = ParseNextInline(str, italicDelimiter, italicStart, inlines, s => new XItalic(s));
                    }<commit_msg>Also catch exception when cannot find end of bold<commit_after>using System;
using System.Collections.Generic;
using System.Linq;

namespace XText
{
    public static class XTextParser
    {
        public static XTextElement Parse(string str)
        {
            str = str.Replace("\r\n", "\n");

            if (str.IndexOf("\n\n", StringComparison.Ordinal) != -1 || str.EndsWith("\n"))
            {
                var isLastAParagraph = str.EndsWith("\n");
                var paragraphs = str.TrimEnd('\n').Split(new[] { "\n\n" }, StringSplitOptions.None);
                var parsed = paragraphs.Select(ParseBlock).ToArray();
                for (var i = 0; i < parsed.Length; i++)
                {
                    var isLast = i == parsed.Length - 1;

                    if (isLast && !isLastAParagraph) continue;
                    if (parsed[i] is XInline) parsed[i] = new XParagraph((XInline) parsed[i]);
                }

                if (paragraphs.Length == 1)
                    return parsed.Single();
                return new XSection(parsed);
            }

            return ParseBlock(str);
        }

        private static XTextElement ParseBlock(string str)
        {
            if (str.StartsWith("  "))
            {
                return new XParagraph(BlockStyle.Indented, str.Substring(2));
            }

            return ParseInlineString(str);
        }

        private static XInline ParseInlineString(string str)
        {
            var inlines = new List<XInline>();
            bool formattedInlineMatch;
            do
            {
                formattedInlineMatch = false;
                const string boldDelimiter = "**";
                const string italicDelimiter = "*";
                var boldStart = str.IndexOf(boldDelimiter, StringComparison.Ordinal);
                var italicStart = str.IndexOf(italicDelimiter, StringComparison.Ordinal);
                var newLineStart = str.IndexOf("\n", StringComparison.Ordinal);

                // Fix escaped characters
                while (italicStart > 0 && str[italicStart - 1] == '\\')
                {
                    // Make sure backslash is not escaped
                    if (italicStart > 1 && str[italicStart - 2] == '\\')
                    {
                        // We are good to fix italicStart
                        var startIndex = italicStart + 1;
                        if (startIndex > str.Length)
                            break;
                        // Remove escape character for *
                        str = str.Remove(italicStart - 1, 1);
                        italicStart = str.IndexOf(italicDelimiter, startIndex, StringComparison.Ordinal);
                    }
                    else
                    {
                        str = str.Remove(italicStart - 1, 1);
                        italicStart = str.IndexOf(italicDelimiter, italicStart, StringComparison.Ordinal);
                        break;
                    }
                }

                if (newLineStart != -1 && 
                    (newLineStart < boldStart || boldStart == -1) &&
                    (newLineStart < italicStart || italicStart == -1))
                {
                    if (newLineStart == 0)
                    {
                        inlines.Add(new XLineBreak());
                        str = str.Substring(1);
                    }
                    else
                    {
                        inlines.Add(new XRun(str.Substring(0, newLineStart)));
                        str = str.Substring(newLineStart + 1);
                        inlines.Add(new XLineBreak());
                    }
                    formattedInlineMatch = true;
                }
                else if (boldStart != -1 && boldStart <= italicStart)
                {
                    try
                    {
                        str = ParseNextInline(str, boldDelimiter, boldStart, inlines, s => new XBold(s));
                    }
                    catch (ArgumentOutOfRangeException)
                    {
                        // No end found
                    }
                    formattedInlineMatch = true;
                }
                else if (italicStart != -1)
                {
                    try
                    {
                        str = ParseNextInline(str, italicDelimiter, italicStart, inlines, s => new XItalic(s));
                    }
{'fraction_non_alphanumeric': 0.0955458112162474, 'fraction_numerical': 0.005308100623124856, 'mean_word_length': 1.1149341142020497, 'pattern_counts': {'":': 0, '<': 13, '<?xml version=': 0, '>': 15, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7357828', 'n_tokens_mistral': 2204, 'n_tokens_neox': 2056, 'n_words': 471}