代码中自动缩进括号的算法

我正在编写代码编辑器(WinForms),我想知道如何使用括号(打开和关闭)来实现{和}的自动缩进function,就像在实际的代码编辑器中一样。

— |> {和}

像这样1:

在此处输入图像描述

编辑器是一个名为rtb的richtextbox。

在阅读和使用代码之前,请阅读以下文本:

  1. 我没有足够的时间来编写更好的代码。 我只是试着为你写一个样本
  2. 我只是以简单的方式编写代码, 而不是OOP
  3. 您可以使用枚举属性其他OOP来改进代码。
  4. 您可以改进代码逻辑 ; 并且您可以使用multithreading来实现更好的性能
  5. 这个样本不彻底 我只为“分号(;)”字符实现了一个Auto-Indention示例

我应该说一些使用代码的提示

  1. rtbCodes是示例项目中表单上的RichTextBox控件名称
  2. frmCodeEditor是示例项目中表单名称

您可以从以下地址下载示例项目:

4Shared – >代码编辑器的自动缩进

SendSpace – >代码编辑器的自动缩进

using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Diagnostics; using System.Drawing; using System.Linq; using System.Text; using System.Windows.Forms; namespace WindowsFormsApplication2 { public partial class frmCodeEditor : Form { char[] chrTracingKeyChars = new char[] { ';', '}', '\n' }; char[] chrCheckingKeyChars = new char[] { '{', '(' }; Point ptCurrentCharPosition; bool bolCheckCalling = false; int intInitialCursorPosition = 0; int intRemainingCharsOfInitialText = 0; int intNextCharIndex = 0; int intPrevCharIndex = 0; public frmCodeEditor() { InitializeComponent(); } private void richTextBox1_TextChanged(object sender, EventArgs e) { AutoIndention(rtbCodes); } ///  /// Implements Auto-Indention. ///  /// A RichTextBox control private void AutoIndention(RichTextBox rtb) { char chrLastChar = GetChar(rtb); if (chrLastChar == chrTracingKeyChars[0]) { intRemainingCharsOfInitialText = rtb.TextLength - rtb.SelectionStart; intInitialCursorPosition = rtb.SelectionStart; ImplementIndentionForSemicolon(rtb); } else if (chrLastChar == chrTracingKeyChars[1]) { ImplementIndentionForRightCurlyBracket(rtb); } else if (chrLastChar == chrTracingKeyChars[2]) { ImplementIndentionForNewLineCharacter(rtb); } } ///  /// Specifies current char based on the cursor position. ///  /// A RichTextBox control /// Returns a char. private char GetChar(RichTextBox rtb) { return GetChar(rtb.SelectionStart, rtb); } ///  /// Specifies a char based on the specified index. ///  /// A char index /// A RichTextBox control /// Returns a char. private char GetChar(int intCharIndex, RichTextBox rtb) { if (intCharIndex != rtb.TextLength) { ptCurrentCharPosition = rtb.GetPositionFromCharIndex(intCharIndex - 1); } else { ptCurrentCharPosition = rtb.GetPositionFromCharIndex(intCharIndex); } return rtb.GetCharFromPosition(ptCurrentCharPosition); } ///  /// Specifies current line number based on the cursor position. ///  /// A RichTextBox control /// Returns the line number. private int GetLineNumber(RichTextBox rtb) { return GetLineNumber(rtb.GetFirstCharIndexOfCurrentLine(), rtb); } ///  /// Specifies the line number based on the specified index. ///  /// A char index /// A RichTextBox control /// Returns the line number. private int GetLineNumber(int intCharIndex, RichTextBox rtb) { return rtb.GetLineFromCharIndex(intCharIndex); } ///  /// Implements indention for semicolon ";" character. ///  /// A RichTextBox control private void ImplementIndentionForSemicolon(RichTextBox rtb) { Dictionary dicResult = IsExistCheckingKeyChars(rtb); if (dicResult[chrCheckingKeyChars[0]] != -1) { int intIndentionLevel = CheckingIndentionLevel(dicResult[chrCheckingKeyChars[0]], rtb); ImplementIndention(dicResult[chrCheckingKeyChars[0]], intIndentionLevel, rtb); } } private void ImplementIndentionForRightCurlyBracket(RichTextBox rtb) { } private void ImplementIndentionForNewLineCharacter(RichTextBox rtb) { } ///  /// Checks current and previous lines for finding key-chars. ///  /// A RichTextBox control /// The search state /// Returns first occurrences of key-chars before current char. private Dictionary IsExistCheckingKeyChars(RichTextBox rtb, bool bolSearchCurrentLine = false) { GetChar(rtb); Dictionary dicCheckingKeyCharsIndexes = new Dictionary(); for (int intCntr = 0; intCntr < chrCheckingKeyChars.Length; intCntr++) { dicCheckingKeyCharsIndexes.Add(chrCheckingKeyChars[intCntr], 0); } for (int intCntr = 0; intCntr < chrCheckingKeyChars.Length; intCntr++) { int intFirstIndexForChecking = 0; int intLastIndexForChecking = 0; for (int intLineCounter = GetLineNumber(rtb); intLineCounter >= 0; intLineCounter--) { if (intLineCounter == GetLineNumber(rtb)) { intLastIndexForChecking = rtb.GetCharIndexFromPosition(ptCurrentCharPosition); } else { intLastIndexForChecking = intFirstIndexForChecking - 1; } intFirstIndexForChecking = rtb.GetFirstCharIndexFromLine(intLineCounter); try { dicCheckingKeyCharsIndexes[chrCheckingKeyChars[intCntr]] = rtb.Find(chrCheckingKeyChars[intCntr].ToString(), intFirstIndexForChecking, rtb.GetCharIndexFromPosition(ptCurrentCharPosition), RichTextBoxFinds.NoHighlight | RichTextBoxFinds.None); if (dicCheckingKeyCharsIndexes[chrCheckingKeyChars[intCntr]] != -1) { do { if (rtb.Find(chrCheckingKeyChars[intCntr].ToString(), intFirstIndexForChecking, rtb.GetCharIndexFromPosition(ptCurrentCharPosition), RichTextBoxFinds.NoHighlight | RichTextBoxFinds.None) != -1) { dicCheckingKeyCharsIndexes[chrCheckingKeyChars[intCntr]] = rtb.Find(chrCheckingKeyChars[intCntr].ToString(), intFirstIndexForChecking, rtb.GetCharIndexFromPosition(ptCurrentCharPosition), RichTextBoxFinds.NoHighlight | RichTextBoxFinds.None); } intFirstIndexForChecking++; } while (intFirstIndexForChecking != rtb.GetCharIndexFromPosition(ptCurrentCharPosition)); break; } } catch { dicCheckingKeyCharsIndexes[chrCheckingKeyChars[intCntr]] = -1; break; } if (bolSearchCurrentLine) { break; } } } return dicCheckingKeyCharsIndexes; } ///  /// Checks a line for calculating its indention level. ///  /// A char index /// A RichTextBox control /// Returns indention level of the line. private int CheckingIndentionLevel(int intCharIndex, RichTextBox rtb) { int intLineNumber = GetLineNumber(intCharIndex, rtb); int intIndentionLevelNumber = 0; intCharIndex = rtb.GetFirstCharIndexFromLine(intLineNumber); char chrChar = GetChar(intCharIndex, rtb); if (chrChar == '\n') { chrChar = GetChar(++intCharIndex, rtb); } if (chrChar != ' ') { return 0; } else { int intSpaceCntr = 0; while(chrChar == ' ') { chrChar = GetChar(++intCharIndex, rtb); if (chrChar == ' ') { intSpaceCntr++; } if (intSpaceCntr % 4 == 0 && intSpaceCntr != 0) { intIndentionLevelNumber++; intSpaceCntr = 0; } } if (intSpaceCntr % 4 != 0) { intIndentionLevelNumber++; } } return intIndentionLevelNumber; } ///  /// Implements Indention to the codes ///  /// A char index /// The number of indention level /// A RichTextBox control private void ImplementIndention(int intCharIndex, int intIndentionLevel, RichTextBox rtb) { intNextCharIndex = intCharIndex; intPrevCharIndex = intCharIndex; int intKeyCharsNumberInLine = 1; int intCurrentLineNumber = GetLineNumber(rtb); int intKeyCharLineNumber = GetLineNumber(intNextCharIndex, rtb); string[] strLinesTexts; Dictionary dicResult; do { rtb.SelectionStart = intPrevCharIndex; dicResult = IsExistCheckingKeyChars(rtb); if (dicResult[chrCheckingKeyChars[0]] != -1) { intKeyCharsNumberInLine++; intPrevCharIndex = dicResult[chrCheckingKeyChars[0]]; } } while (dicResult[chrCheckingKeyChars[0]] != -1); if (!bolCheckCalling) { if (intCurrentLineNumber == intKeyCharLineNumber) { for (int intCntr = 1; intCntr <= intKeyCharsNumberInLine; intCntr++) { do { rtb.SelectionStart = intPrevCharIndex; dicResult = IsExistCheckingKeyChars(rtb, true); if (dicResult[chrCheckingKeyChars[0]] != -1) { intPrevCharIndex = dicResult[chrCheckingKeyChars[0]]; } } while (dicResult[chrCheckingKeyChars[0]] != -1); bolCheckCalling = true; ImplementIndention(intPrevCharIndex, rtb); } return; } } bolCheckCalling = false; rtb.SelectionStart = intNextCharIndex; rtb.SelectionLength = 1; rtb.SelectedText = "\n" + rtb.SelectedText; intCurrentLineNumber = GetLineNumber(rtb); strLinesTexts = rtb.Lines; strLinesTexts[intCurrentLineNumber] = strLinesTexts[intCurrentLineNumber].Trim(); for (int intIndentionCntr = 1; intIndentionCntr <= intIndentionLevel; intIndentionCntr++) { for (int intSpaceCntr = 1; intSpaceCntr <= 4; intSpaceCntr++) { strLinesTexts[intCurrentLineNumber] = ' ' + strLinesTexts[intCurrentLineNumber]; } } rtb.Lines = strLinesTexts; rtb.SelectionStart = intNextCharIndex + ((intIndentionLevel * 4) + 1); intNextCharIndex = rtb.SelectionStart; rtb.SelectionLength = 1; rtb.SelectedText = rtb.SelectedText + "\n"; intCurrentLineNumber = GetLineNumber(rtb); strLinesTexts = rtb.Lines; strLinesTexts[intCurrentLineNumber] = strLinesTexts[intCurrentLineNumber].Trim(); for (int intIndentionCntr = 1; intIndentionCntr <= intIndentionLevel + 1; intIndentionCntr++) { for (int intSpaceCntr = 1; intSpaceCntr <= 4; intSpaceCntr++) { strLinesTexts[intCurrentLineNumber] = ' ' + strLinesTexts[intCurrentLineNumber]; } } rtb.Lines = strLinesTexts; rtb.SelectionStart = intInitialCursorPosition + ((rtb.TextLength - intInitialCursorPosition) - intRemainingCharsOfInitialText); intNextCharIndex = rtb.SelectionStart; intPrevCharIndex = intNextCharIndex; } ///  /// Implements Indention to the codes ///  /// A char index /// A RichTextBox control private void ImplementIndention(int intCharIndex, RichTextBox rtb) { int intIndentionLevel = CheckingIndentionLevel(intCharIndex, rtb); ImplementIndention(intCharIndex, intIndentionLevel, rtb); } } } 

我希望这个示例代码可以帮助您。

如果您改进,请更新和共享代码。

好吧,我的解决方案是错误的,但它足以让你了解它是如何工作的

我的结果:

 { { { } } } 

在这里我的代码

 public partial class Form1 : Form { private bool FLAG_Selftimer = false; private bool FLAG_KeyPressed = false; private int pos = 0; public Form1() { InitializeComponent(); } private void richTextBox1_TextChanged(object sender, EventArgs e) { var rtb = sender as RichTextBox; var point = rtb.SelectionStart; if (!FLAG_Selftimer) { rtb.Text = ReGenerateRTBText(rtb.Text); FLAG_KeyPressed = false; } else { point ++; FLAG_Selftimer = false; } rtb.SelectionStart = point; } private string ReGenerateRTBText(string Text) { string[] text = Regex.Split(Text,"\n"); int lvl = 0; string newString = ""; foreach (string line in text) { line.TrimStart(' '); newString += indentation(lvl) + line.TrimStart(' ') + "\n"; if (line.Contains("{")) lvl++; if (line.Contains("}")) lvl--; } FLAG_Selftimer = true; return (!FLAG_KeyPressed) ? newString : newString.TrimEnd('\n'); } private string indentation(int IndentLevel) { string space = ""; if(IndentLevel>0) for (int lvl = 0; lvl < IndentLevel; lvl++) { space += " ".PadLeft(8); } return space; } private void richTextBox1_KeyPress(object sender, KeyPressEventArgs e) { FLAG_KeyPressed = true; } } 

我希望这能帮到您