C # amateur programmer: Code Critique

I have done this before, and it was very helpful to me. I am an amateur programmer and do not have more experienced programmers around me to help and help me grow. Any feedback on this criticism is greatly appreciated!

I have a C # class that takes some basic markup from the user (usually from the base text field) and outputs a beautifully formatted HTML table. I have included markup, HTML output and source code below. Again, all feedback / constructive criticism is welcome.

I am also curious how long it will take an experienced programmer? It took me about 6-6.5 hours.

Markup

[grid]
border=0, align=center, width=95%
|(c=vdsa) VDS-A|(c=vdsb) VDS-B|(c=vdsc featured) VDS-C
RAM|1GB|2GB|(c=featured) 4GB
CPU|(c=nofeature)|(c=nofeature)
<a href="http://www.google.com">Google</a>|(c=yesfeature)|(c=nofeature)|(C=nofeature)
[/grid]

HTML output

<table align="center" border="0" width="95%">
    <tr>
            <th></th><th class="vdsa">VDS-A</th><th class="vdsb">VDS-B</th><th class="vdsc featured">VDS-C</th>
    </tr><tr>
            <td>RAM</td><td>1GB</td><td>2GB</td><td class="featured">4GB</td>
    </tr><tr>
            <td>CPU</td><td class="nofeature"></td><td class="nofeature" colspan="2"></td>
    </tr><tr>
            <td><a href="http://www.google.com">Google</a></td><td class="yesfeature"></td><td class="nofeature"></td><td class="nofeature"></td>
    </tr>
</table>

C # class

using System;
using System.IO;
using System.Linq;
using System.Text;
using System.Web.UI;

namespace GridMarkup
{
    public class GridProcessor
    {
        public string MarkupOpenTag { get; set; }
        public string MarkupCloseTag { get; set; }
        public string[] AllowedTableOptions { get; set; }

        private string[] _rowSplitter = { "\r\n" };
        private char _columnSplitter = '|';
        private string _optionAssignmentOperator = "=";
        private char[] _optionEndOperators = { ',', '\r', '\n', ' ' };
        private int _columnsInGrid = -1;
        private string _cssAssignmentOperator = "(c=";
        private string _cssEndOperator = ")";

        public GridProcessor() {
            MarkupOpenTag = "[grid]";
            MarkupCloseTag = "[/grid]";
            AllowedTableOptions = new string[] { "align", "border", "cellpadding", "cellspacing", "width" };
        }

        public string Transform(string text)
        {
            if (string.IsNullOrEmpty(text)) return "";

            string output = string.Empty;
            int currentCurserLocation = 0;

            while (currentCurserLocation < text.Length)
            {
                // try to find an opening grid tag.
                int gridStart = text.ToLower().IndexOf(MarkupOpenTag.ToLower(), currentCurserLocation);
                if (gridStart > -1)
                {
                    // we have our opening tag, try to find an end tag.
                    int gridEnd = text.ToLower().IndexOf(MarkupCloseTag.ToLower(), currentCurserLocation);
                    if (gridEnd > -1)
                    {
                        // we have ourselves a grid! check for data between grids.
                        if (gridStart > currentCurserLocation)
                        {
                            output += text.Substring(currentCurserLocation, gridStart - currentCurserLocation);
                        }

                        // let get the data out of the grid.
                        string gridText = text.Substring(gridStart + MarkupOpenTag.Length, gridEnd - gridStart - MarkupOpenTag.Length);
                        output += ProcessGrid(gridText);

                        // we are done with this grid, move the curser forward.
                        currentCurserLocation = gridEnd + MarkupCloseTag.Length;
                    }
                    else
                    {
                        output += text.Substring(currentCurserLocation, text.Length - currentCurserLocation);
                        currentCurserLocation = text.Length;
                    }
                }
                else
                {
                    output += text.Substring(currentCurserLocation, text.Length - currentCurserLocation);
                    currentCurserLocation = text.Length;
                }
            }

            return output;
        }

        private string ProcessGrid(string gridText)
        {
            StringBuilder sb = new StringBuilder();
            string[] gridRows = gridText.Split(_rowSplitter, StringSplitOptions.RemoveEmptyEntries);

            using (HtmlTextWriter writer = new HtmlTextWriter(new StringWriter(sb)))
            {

                //for the first line, check for table options
                int startIndex = 0;
                bool optionsFound = false;

                foreach (string option in AllowedTableOptions)
                {
                    int optionStart = gridRows[0].ToLower().IndexOf(option.ToLower() + _optionAssignmentOperator);
                    if (optionStart > -1)
                    {
                        int optionEnd = gridRows[0].ToLower().IndexOfAny(_optionEndOperators, optionStart);
                        if (optionEnd == -1)
                            optionEnd = gridRows[0].Length;

                        writer.AddAttribute(option, gridRows[0].Substring(optionStart + option.Length + 1, optionEnd - optionStart - option.Length - 1));
                        optionsFound = true;
                    }
                }

                if (optionsFound)
                    startIndex += 1;

                writer.RenderBeginTag(HtmlTextWriterTag.Table);

                for (int i = startIndex; i < gridRows.Count(); i++)
                {
                    ProcessGridRow(gridRows[i], writer, (i == startIndex) ? HtmlTextWriterTag.Th : HtmlTextWriterTag.Td);
                }

                writer.RenderEndTag(); // end table

            }

            return sb.ToString();
        }

        private void ProcessGridRow(string rowText, HtmlTextWriter writer, HtmlTextWriterTag dataTag)
        {
            string[] rowColumns = rowText.Split(_columnSplitter);
            int rowColumnsCount = rowColumns.Count();
            int colSpan = 0;

            // this is our header, so it defines the number of columns
            if (dataTag == HtmlTextWriterTag.Th)
                _columnsInGrid = rowColumnsCount;

            writer.RenderBeginTag(HtmlTextWriterTag.Tr);
            for (int i = 0; i < rowColumnsCount; i++)
            {
                // if this is the last column, check to see if we need to set a colspan
                if (i == rowColumnsCount - 1)
                    colSpan = _columnsInGrid - rowColumnsCount + 1;

                ProcessGridColumn(rowColumns[i], writer, dataTag, colSpan);
            }
            writer.RenderEndTag(); // end tr
        }

        private void ProcessGridColumn(string columnText, HtmlTextWriter writer, HtmlTextWriterTag dataTag, int colSpan)
        {
            string innerColumnText = columnText;

            // check to see if there are any css class assignments
            int cssStart = columnText.ToLower().IndexOf(_cssAssignmentOperator.ToLower());
            if (cssStart > -1)
            {
                // we found the start of a css assignment, lets see if we can find the end
                int cssEnd = columnText.IndexOf(_cssEndOperator, cssStart + _cssAssignmentOperator.Length);
                if (cssEnd > -1)
                {
                    // we've got the end, now lets add the css attribute.
                    string cssClasses = columnText.Substring(cssStart + _cssAssignmentOperator.Length, cssEnd - cssStart - _cssAssignmentOperator.Length);
                    writer.AddAttribute(HtmlTextWriterAttribute.Class, cssClasses);
                    innerColumnText = columnText.Remove(cssStart, _cssAssignmentOperator.Length + _cssEndOperator.Length + cssClasses.Length).Trim();
                }
            }

            if (colSpan > 1)
                writer.AddAttribute(HtmlTextWriterAttribute.Colspan, colSpan.ToString());

            writer.RenderBeginTag(dataTag);
            writer.Write(innerColumnText);
            writer.RenderEndTag();
        }
    }
}
+5
source share
6

, :

  • ; GridProcessor , . . , ( MyMarkup), MyMarkupTransformer MyMarkupHtmlTransformer.

  • ; .

  • , , _columnSplitter, const readonly ( ).

  • MarkupOpenTag MarkupCloseTag, , , () DRY, , ( , ).

  • +=. StringBuilder.

  • Cursor (, ).

  • ToLower().IndexOf() (i18n; n.b. Turkish i). IndexOf, StringComparison.

  • , , . , . . .

  • if .

  • , HtmlTextWriterTag , HtmlTextWriterAttribute . , , .

  • - - , Microsoft , StyleCop .

/, , , , . , IDisposable , using, . , , , , "" .

, , , - , .

+5

.

  • - . , . , . ReadOnlyCollection .

  • , . , " " " ". . , , . , . .

, , , , , .

+7

. LL (1), .


LL (1) , BNF . :

definition :== griddef { griddef }
griddef :== gridstart gridbody gridend
gridstart :== "[grid]" gridattributes
gridattributes :== { gridattribute }
gridattribute :== borderdef | aligndef | widthdef
...

:

bool ParseDefinition()
{
    if (!ParseGridDef())
        return false;
    while(ParseGridDef())
        ;
    return true;
}

bool ParseGridDef()
{
    return ParseGridStart() && ParseGridBody() && ParseGridEnd();
}

bool ParseGridStart()
{
    if (!AssureRead("[grid]"))
        return false;
    while (ReadGridAttribute())
        ;
    return true;
}

bool ReadGridAttribute()
{
    return ReadBorderDef() || ReadAlignDef() || ReadWidthDef();
}

.

+2

, , , , , , , .

, , , , , , , .

, , . , .

, , - 'output'. , . , StringBuilder. , .

StringBuilder builder = new StringBuilder();
builder.Append("whatever");
return builder.ToString();

, , . .:)

, ... , , , , , 1,5 , , , , , , 3-4. , . , , .;)

+2

, . " " LL (1) . , ANTLR. , () (html- ).

0

, . , .

, rdp parseGrid(), parseRow() parseColumn(), .

0

All Articles