2014-02-11 5 views
8

Я хотел бы правильно отложить некоторый код VB.NET, содержащийся в текстовом файле. Есть ли способ сделать это?Есть ли способ автоматически вставить код VB.NET в текстовый файл

например. Начните с этого:

Public Shared Function CanReachPage(page As String) As Boolean 
Try 
Using client = New WebClient() 
Using stream = client.OpenRead(page) 
Return True 
End Using 
End Using 
Catch 
Return False 
End Try 
End Function 

закончить с этим:

Public Shared Function CanReachPage(page As String) As Boolean 
    Try 
     Using client = New WebClient() 
      Using stream = client.OpenRead(page) 
       Return True 
      End Using 
     End Using 
    Catch 
     Return False 
    End Try 
End Function 

Все, что я искал до сих пор привел меня к IndentedTextWriter класса, но единственные примеры, которые я нашел это вручную отступа строки как это: .NET Console TextWriter that Understands Indent/Unindent/IndentLevel

Дополнительный кредит: Я хотел бы также добавить правильный интервал, а также, если это возможно:

например Dim i As String="Hello"+"GoodBye" ->Dim i As String = "Hello" + "GoodBye"

+0

Этот пример консоли, который вы нашли, работает не только на консоли. Это TextWriter, как и StreamWriter. Так что просто делайте это так же, передавая TextWriter через конструктор. –

+0

@HansPassant - да, я собрал это, но не получается, что такое отступы? Он полагается на меня, зная, что «если строка начинается с« Использование », я должен отступать на один уровень» и т. Д. И т. Д. –

+0

Ох. Да, написание того, что понимает синтаксис vb.net, - это совершенно другая игра с мячом. Раньше это было легко, но продолжение линии в наши дни необязательно, что должно дать вам серьезную мигрень. –

ответ

0

Я решил, что у вас есть трещина при прокатке. Есть некоторые крайние случаи, что это не работает на 100% для, но это довольно надежно:

Public Class VBIndenter 

    Private _classIndents As New List(Of Integer) 
    Private _moduleIndents As New List(Of Integer) 
    Private _subIndents As New List(Of Integer) 
    Private _functionIndents As New List(Of Integer) 
    Private _propertyIndents As New List(Of Integer) 
    Private _structureIndents As New List(Of Integer) 
    Private _enumIndents As New List(Of Integer) 
    Private _usingIndents As New List(Of Integer) 
    Private _withIndents As New List(Of Integer) 
    Private _ifIndents As New List(Of Integer) 
    Private _tryIndents As New List(Of Integer) 
    Private _getIndents As New List(Of Integer) 
    Private _setIndents As New List(Of Integer) 
    Private _forIndents As New List(Of Integer) 
    Private _selectIndents As New List(Of Integer) 
    Private _doIndents As New List(Of Integer) 
    Private _whileIndents As New List(Of Integer) 

    Public Property IndentWidth As Integer = 4 
    Public Property IndentChar As Char = " "c 

    Public Sub Indent(txt As TextBox) 

     Dim lastLabelIndent As Integer = 0 
     Dim lastRegionIndent As Integer = 0 
     Dim currentIndent As Integer = 0 
     Dim inProperty As Boolean = False 
     Dim lineText As String 
     Dim newLineIndent As Integer 
     Dim lines As String() = txt.Lines 

     For i As Integer = 0 To lines.Count - 1 

      Dim line = lines(i) 

      'get the trimmed line without any comments 
      lineText = StripComments(line) 

      'only change the indent on lines that are code 
      If lineText.Length > 0 Then 

       'special case for regions and labels - they always have zero indent 
       If lineText.StartsWith("#") Then 
        lastRegionIndent = currentIndent 
        currentIndent = 0 
       ElseIf lineText.EndsWith(":") Then 
        lastLabelIndent = currentIndent 
        currentIndent = 0 
       End If 

       'if we are in a property and we see something 
       If (_propertyIndents.Count > 0) Then 
        If Not lineText.StartsWith("End") Then 
         If lineText.StartsWith("Class ") OrElse lineText.Contains(" Class ") Then 
          _propertyIndents.RemoveAt(_propertyIndents.Count - 1) 
          currentIndent -= 1 
         ElseIf lineText.StartsWith("Module ") OrElse lineText.Contains(" Module ") Then 
          _propertyIndents.RemoveAt(_propertyIndents.Count - 1) 
          currentIndent -= 1 
         ElseIf lineText.StartsWith("Sub ") OrElse lineText.Contains(" Sub ") Then 
          _propertyIndents.RemoveAt(_propertyIndents.Count - 1) 
          currentIndent -= 1 
         ElseIf lineText.StartsWith("Function ") OrElse lineText.Contains(" Function ") Then 
          _propertyIndents.RemoveAt(_propertyIndents.Count - 1) 
          currentIndent -= 1 
         ElseIf lineText.StartsWith("Property ") OrElse lineText.Contains(" Property ") Then 
          _propertyIndents.RemoveAt(_propertyIndents.Count - 1) 
          currentIndent -= 1 
         ElseIf lineText.StartsWith("Structure ") OrElse lineText.Contains(" Structure ") Then 
          _propertyIndents.RemoveAt(_propertyIndents.Count - 1) 
          currentIndent -= 1 
         ElseIf lineText.StartsWith("Enum ") OrElse lineText.Contains(" Enum ") Then 
          _propertyIndents.RemoveAt(_propertyIndents.Count - 1) 
          currentIndent -= 1 
         End If 
        Else 
         If lineText = "End Class" Then 
          _propertyIndents.RemoveAt(_propertyIndents.Count - 1) 
         End If 
        End If 
       End If 

       If lineText = "End Class" Then 
        currentIndent = _classIndents.Item(_classIndents.Count - 1) 
        _classIndents.RemoveAt(_classIndents.Count - 1) 
       ElseIf lineText = "End Module" Then 
        currentIndent = _moduleIndents.Item(_moduleIndents.Count - 1) 
        _moduleIndents.RemoveAt(_moduleIndents.Count - 1) 
       ElseIf lineText = "End Sub" Then 
        currentIndent = _subIndents.Item(_subIndents.Count - 1) 
        _subIndents.RemoveAt(_subIndents.Count - 1) 
       ElseIf lineText = "End Function" Then 
        currentIndent = _functionIndents.Item(_functionIndents.Count - 1) 
        _functionIndents.RemoveAt(_functionIndents.Count - 1) 
       ElseIf lineText = "End Property" Then 
        currentIndent = _propertyIndents.Item(_propertyIndents.Count - 1) 
        _propertyIndents.RemoveAt(_propertyIndents.Count - 1) 
       ElseIf lineText = "End Try" Then 
        currentIndent = _tryIndents.Item(_tryIndents.Count - 1) 
        _tryIndents.RemoveAt(_tryIndents.Count - 1) 
       ElseIf lineText = "End With" Then 
        currentIndent = _withIndents.Item(_withIndents.Count - 1) 
        _withIndents.RemoveAt(_withIndents.Count - 1) 
       ElseIf lineText = "End Get" Then 
        currentIndent = _getIndents.Item(_getIndents.Count - 1) 
        _getIndents.RemoveAt(_getIndents.Count - 1) 
       ElseIf lineText = "End Set" Then 
        currentIndent = _setIndents.Item(_setIndents.Count - 1) 
        _setIndents.RemoveAt(_setIndents.Count - 1) 
       ElseIf lineText = "End If" Then 
        currentIndent = _ifIndents.Item(_ifIndents.Count - 1) 
        _ifIndents.RemoveAt(_ifIndents.Count - 1) 
       ElseIf lineText = "End Using" Then 
        currentIndent = _usingIndents.Item(_usingIndents.Count - 1) 
        _usingIndents.RemoveAt(_usingIndents.Count - 1) 
       ElseIf lineText = "End Structure" Then 
        currentIndent = _structureIndents.Item(_structureIndents.Count - 1) 
        _structureIndents.RemoveAt(_structureIndents.Count - 1) 
       ElseIf lineText = "End Select" Then 
        currentIndent = _selectIndents.Item(_selectIndents.Count - 1) 
        _selectIndents.RemoveAt(_selectIndents.Count - 1) 
       ElseIf lineText = "End Enum" Then 
        currentIndent = _enumIndents.Item(_enumIndents.Count - 1) 
        _enumIndents.RemoveAt(_enumIndents.Count - 1) 
       ElseIf lineText = "End While" OrElse lineText = "Wend" Then 
        currentIndent = _whileIndents.Item(_whileIndents.Count - 1) 
        _whileIndents.RemoveAt(_whileIndents.Count - 1) 
       ElseIf lineText = "Next" OrElse lineText.StartsWith("Next ") Then 
        currentIndent = _forIndents.Item(_forIndents.Count - 1) 
        _forIndents.RemoveAt(_forIndents.Count - 1) 
       ElseIf lineText = "Loop" OrElse lineText.StartsWith("Loop ") Then 
        currentIndent = _doIndents.Item(_doIndents.Count - 1) 
        _doIndents.RemoveAt(_doIndents.Count - 1) 
       ElseIf lineText.StartsWith("Else") Then 
        currentIndent = _ifIndents.Item(_ifIndents.Count - 1) 
       ElseIf lineText.StartsWith("Catch") Then 
        currentIndent = _tryIndents.Item(_tryIndents.Count - 1) 
       ElseIf lineText.StartsWith("Case") Then 
        currentIndent = _selectIndents.Item(_selectIndents.Count - 1) + 1 
       ElseIf lineText = "Finally" Then 
        currentIndent = _tryIndents.Item(_tryIndents.Count - 1) 
       End If 

      End If 

      'find the current indent 
      newLineIndent = currentIndent * Me.IndentWidth 
      'change the indent of the current line 
      line = New String(IndentChar, newLineIndent) & line.TrimStart 
      lines(i) = line 

      If lineText.Length > 0 Then 
       If lineText.StartsWith("#") Then 
        currentIndent = lastRegionIndent 
       ElseIf lineText.EndsWith(":") Then 
        currentIndent = lastLabelIndent 
       End If 

       If Not lineText.StartsWith("End") Then 
        If (lineText.StartsWith("Class ") OrElse lineText.Contains(" Class ")) Then 
         _classIndents.Add(currentIndent) 
         currentIndent += 1 
        ElseIf (lineText.StartsWith("Module ") OrElse lineText.Contains(" Module ")) Then 
         _moduleIndents.Add(currentIndent) 
         currentIndent += 1 
        ElseIf (lineText.StartsWith("Sub ") OrElse lineText.Contains(" Sub ")) Then 
         _subIndents.Add(currentIndent) 
         currentIndent += 1 
        ElseIf (lineText.StartsWith("Function ") OrElse lineText.Contains(" Function ")) Then 
         _functionIndents.Add(currentIndent) 
         currentIndent += 1 
        ElseIf (lineText.StartsWith("Property ") OrElse lineText.Contains(" Property ")) Then 
         _propertyIndents.Add(currentIndent) 
         currentIndent += 1 
        ElseIf (lineText.StartsWith("Structure ") OrElse lineText.Contains(" Structure ")) Then 
         _structureIndents.Add(currentIndent) 
         currentIndent += 1 
        ElseIf (lineText.StartsWith("Enum ") OrElse lineText.Contains(" Enum ")) Then 
         _enumIndents.Add(currentIndent) 
         currentIndent += 1 
        ElseIf lineText.Contains("Using ") Then 
         _usingIndents.Add(currentIndent) 
         currentIndent += 1 
        ElseIf lineText.StartsWith("Select Case") Then 
         _selectIndents.Add(currentIndent) 
         currentIndent += 1 
        ElseIf lineText = "Try" Then 
         _tryIndents.Add(currentIndent) 
         currentIndent += 1 
        ElseIf lineText = "Get" Then 
         _getIndents.Add(currentIndent) 
         currentIndent += 1 
        ElseIf lineText.StartsWith("Set") AndAlso Not lineText.Contains("=") Then 
         _setIndents.Add(currentIndent) 
         currentIndent += 1 
        ElseIf lineText.StartsWith("With") Then 
         _withIndents.Add(currentIndent) 
         currentIndent += 1 
        ElseIf lineText.StartsWith("If") AndAlso lineText.EndsWith("Then") Then 
         _ifIndents.Add(currentIndent) 
         currentIndent += 1 
        ElseIf lineText.StartsWith("For") Then 
         _forIndents.Add(currentIndent) 
         currentIndent += 1 
        ElseIf lineText.StartsWith("While") Then 
         _whileIndents.Add(currentIndent) 
         currentIndent += 1 
        ElseIf lineText.StartsWith("Do") Then 
         _doIndents.Add(currentIndent) 
         currentIndent += 1 
        ElseIf lineText.StartsWith("Case") Then 
         currentIndent += 1 
        ElseIf lineText.StartsWith("Else") Then 
         currentIndent = _ifIndents.Item(_ifIndents.Count - 1) + 1 
        ElseIf lineText.StartsWith("Catch") Then 
         currentIndent = _tryIndents.Item(_tryIndents.Count - 1) + 1 
        ElseIf lineText = "Finally" Then 
         currentIndent = _tryIndents.Item(_tryIndents.Count - 1) + 1 
        End If 
       End If 
      End If 
     Next 
     'update the textbox 
     txt.Lines = lines 
    End Sub 

    Private Function StripComments(ByVal code As String) As String 
     If code.IndexOf("'"c) >= 0 Then 
      code = code.Substring(0, code.IndexOf("'"c)) 
     End If 
     Return code.Trim 
    End Function 
End Class 

Использование:

Поместите код в TextBox (TextBox1), а затем вызвать индентора, как это :

Dim id As New VBIndenter 
id.Indent(TextBox1) 
2

Если вы используете Visual Studio (я смотрю на VS 2010 на данный момент; Я не знаю, что раньше делали предыдущие версии), затем вы можете перейти в Редактировать-> Расширенный-> Формат документа, и он должен позаботиться о том, чтобы отступы и интервалы для вас.

Обратите внимание, что это работает для любого типа документа, который понимает Visual Studio. Я регулярно использую этот трюк для форматирования XML-документов во что-то разборчивое.

+1

. Ярлык для Формат документа - Ctrl-K Ctrl-D. –

+0

Спасибо, но я хочу сделать это на машине, на которой нет установленного VS –

+1

Форматирование кода VB без использования IDE является довольно значительным ограничением. Как упоминалось выше, @HansPassant, писать собственный VB-парсер будет нетривиальным начинанием. Вы действительно не говорили о том, почему вы пытаетесь это сделать, но, по крайней мере, стоит подумать о том, нужно ли устанавливать [бесплатно] (http: //www.visualstudio.com/en-US/products/visual-studio-express-vs), начальная версия Visual Studio на рассматриваемом компьютере может оказаться полезной, если только использовать для форматирования ваших файлов. – shooley

1

Если вы хорошо с помощью предварительной версии программного обеспечения, вы можете использовать Roslyn:

Dim parsed = Syntax.ParseCompilationUnit(text) 
Dim normalized = parsed.NormalizeWhitespace() 
Console.WriteLine(normalized) 
-3

Один из способов сделать это, чтобы построить анализатор и prettyprinter. Синтаксический анализатор считывает исходный код и строит АСТ, фиксируя сущность структуры программы. Симпатичный принтер берет дерево, и регенерирует выход на основе структуры; таким образом, это «легко» для получения структурированного вывода. В качестве ключевого намека на каждый уровень языковая структура (классы, методы, блоки, циклы, условные выражения), , симпатичный принтер может отпечатать текст с отпечатками, чтобы дать хорошую структуру отступов.

Разборчивость и красивая печать - довольно сложные темы. Вместо повторения всего этого здесь вы можете увидеть мой SO answer on how to parse, with follow on discussion on how to build an AST. Prettyprinting не так хорошо известна, , но this SO answer of mine дает довольно полное описание о том, как это сделать.

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

Учитывая программу niceprinter, OP может просто запустить ее как процесс форматирования файла.

Если вы это сделаете, то да, вы можете форматировать текст VB.net. Наш (автономный) форматировщик VB.net («DMSFormat ...») делает это выше, чтобы добиться красивой печати.

Учитывая файл "vb_example.сеть ":

Module Test 
Public Shared Function CanReachPage(page As String) As Boolean 
Try 
Using client = New WebClient() 
Using stream = client.OpenRead(page) 
Return True 
End Using 
End Using 
Catch 
Return False 
End Try 
End Function 
End Module 

Следующая:

C:>DMSFormat VisualBasic~VBdotNet C:\temp\vb_example.net 

производит:

VisualBasic~VBdotNet Formatter/Obfuscator Version 1.2.1 
Copyright (C) 2010 Semantic Designs, Inc 
Powered by DMS (R) Software Reengineering Toolkit 
Parsing C:\temp\vb_example.net [encoding ISO-8859-1] 


Module Test 
    Public Shared Function CanReachPage(page As String) As Boolean 
    Try 
     Using client = New WebClient() 
     Using stream = client.OpenRead(page) 
      Return True 
     End Using 
     End Using 
    Catch 
     Return False 
    End Try 
    End Function 
End Module 

который идентичен тому, что ОП хотел в своем примере

Вы можете легко направим отформатирован. содержимого программы в файл.

Вы можете предоставить инструменту файл проекта, и он будет отформатировать столько файлов, сколько вы указываете в файле проекта сразу.

Форматирует интегрированный полный парсер VB.net, и наш собственный весьма печатный механизм. Он анализирует текст источника точно (включая странный символ кодировок). Поскольку он использует надежный синтаксический анализатор и niceprinter, он не нарушит код.

Версия eval работает с файлами из нескольких сотен строк кода. Это может быть именно то, что вам нужно.

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

+0

Это здорово и все, но вы не указали, где этот инструмент, кто упоминает, кто такой «наш». – RubberDuck

+0

Это потому, что объекты политики SO и я беру огромный колосок, когда отправляю ссылки на «наши» инструменты. «Наш» означает именно это; проверьте мою биографию. Если вы считаете, что эти ограничения неверны, запишите их в Meta. –

+1

Без этой информации этот ответ совершенно бесполезен. Я не тот, кто должен заниматься мета. Вы должны быть. Фактически, вы найдете, что такие ответы [совершенно приемлемы] (http://meta.stackexchange.com/a/59302/256822), потому что он * напрямую связывает * с вопросом. – RubberDuck

Смежные вопросы