I'm having a bit of trouble getting an expression to work to replace the entire contents of a function. For example
void function1 (void)
{
Some junk here();
Other Junk here
{
Blah blah blah
}
}
I'd Like to replace the contents of this function with some predefined value ie
void function1 (void)
{
Something else here
}
This is what I have currently however it doesn't seem to work. I was trying to capture the first part of the function and then the ending curly brace which is on a new line by itself. I'm pretty new to regular expressions so forgive me if it makes no sense
text = Regex.Replace(text, #"(function1)*?(^}$))", Replace, RegexOptions.Multiline);
Any ideas what I am doing wrong or how I should go about this differently?
This is what I came up with. Let me know if it works for you.
public static string Replace_Function_Contents(string old_function, string new_contents)
{
Regex function_match = new Regex(#"(\s){1,}?([\s\w]{1,})?(\s{1,})?\(.{1,}?\)(\s{1,}){");
var match = function_match.Match(old_function);
return old_function.Remove(match.Index + match.Length) + new_contents + "}";
}
This seems to work:
/function1(?:.|\n)*?^}/m
See http://regexr.com/3geoq.
I think the major issue with your regular expression was (function1)*, which matches the string "function1" zero or more times. Example matching strings are "" and "function1function1function1". You probably meant (function1).*, but unless things work differently in .NET's regular expression engine, the . won't match newlines. I used (?:.|\n) instead to include newlines. I also dropped the captures, since your response to my question about back references didn't seem to indicate you were actually using them.
You also had an extra right parenthesis in your regular expression that I would have expected to cause an error.
Full working C# code:
using System;
using System.Text.RegularExpressions;
namespace regex
{
class Program
{
static void Main(string[] args)
{
var text = #"something up here
void anotherfunc(int x)
{
}
void function1 (void)
{
Some junk here();
Other Junk here
{
Blah blah blah
}
}
int main()
{
}";
var replacement = #"function1 (void)
Something else here
}";
Console.Out.WriteLine(Regex.Replace(text, #"function1(?:.|\n)*?^}", replacement, RegexOptions.Multiline));
}
}
}
Output:
something up here
void anotherfunc(int x)
{
}
void function1 (void)
Something else here
}
int main()
{
}
Related
I have sample data
string test = #"allprojects {
repositories {
test()
}
}"
When I read the test, I should get the exact string with spaces/tabs/new lines instead of me writing Environment.NewLine etc wherever it requires new line. When I print, it should print the same format [WYSIWYG] type.
Presently it gives something like this in debugger allprojects {\r\n\t\t repositories { \r\n\t\t test() \r\n\t\t } \r\n\t\t }
There are several ways to determine a new line, and it is dependant on the OS you are using:
Windows: \r\n
Unix: \n
Mac: \r
As for a tab, all you need is \t.
Therefore, in your string all you need is:
string test = #"allprojects {\r\n\trepositories {\r\n\t\ttest()\r\n\t}\r\n}"
Which will output:
allprojects {
repositories {
test()
}
}
What I do in string literals that need this is just not indent the content at all:
namespace Foo {
class Bar {
const string test = #"
allprojects {
repositories {
test()
}
}";
}
}
And strip away the initial newline. Looks a bit ugly, but it does get the point across that the leading whitespace matters.
You can also place the #" on the second chance, but automatic code formatting could move that and it doesn't look as close to the actual text. (Code formatting should not touch the contents of a string, but I can't guarantee that.)
This should round-trip correctly if processing the string line-by-line, as would seem appropriate anyway:
var reader = new StringReader(test);
reader.ReadLine();
string line;
while ((line = reader.ReadLine()) != null)
{
Console.WriteLine(line);
}
Console.ReadLine();
Or just read them from a file / resource.
I am reading the The Pragmatic programmer and doing the following exercise in .net world (Chapter 3 - Code Generators)
The Exercise
"Write a code generator that takes the input in Listing 1, and generates output in two languages of your choice. Try to make it easy to add new languages."
Listing 1
# Add a product
# to the 'on-order' list
M AddProduct
F id int
F name char[30]
F order_code int
E
How would you implement the solution in T4 or anything else in .net world (CodeDOM is too complex) so that we can generate the code in c# and in one other .net language (visual basic or IronRuby etc.)
I know you say CodeDOM is too complex, but I would suggest using CodeDOM =). Here's a short example to start with: http://asp.dotnetheaven.com/howto/doc/listbuilder.aspx. For your example, you probably want to add a CodeMemberMethod to CodeTypeDeclaration's members - MSDN has some examples.
T4 could work, but it I don't think it's really ideal for this situation.
I don't think this is intended to be an exercise in working with existing code generators. Actually there's much more to it. The goal, I believe, is to build your own code generator, domain-specific language and deal with concepts like parsing and extensibility/pluggability. Perhaps I am reading too much into the exercise, but perhaps it's more about developing core developer skills/knowledge than educating oneself on existing tools.
Taking Ben Griswold advice, I think it is a good idea to implement it myself. And while just a little into implementing code generator in C#, I realized few things -
1. Need text manipulation language like Python etc.
2. Need to learn Regular expressions
I do intend to implement it in Ruby but for now, I implemented it in C# as -
static void Main(string[] args)
{
CodeGenerator gen = new CodeGenerator();
gen.ReadFile("Input.txt");
}
public class CodeGenerator
{
public void ReadFile(string filename)
{
StreamReader fs = new StreamReader(filename);
string line;
CSharpCode CG = new CSharpCode();
while ((line = fs.ReadLine()) != null)
{
line = line.TrimEnd('\n');
if (Regex.IsMatch(line, #"^\s*S"))
CG.BlankLine();
else if (Regex.IsMatch(line, #"^\#(.*)")) // match comments
CG.Comment(line.TrimStart('#'));
else if (Regex.IsMatch(line, #"^M\s*(.+)")) // start msg
CG.StartMsg(line.Split(' ')[1]);
else if (Regex.IsMatch(line, #"^E")) // end msg
CG.EndMsg();
else if (Regex.IsMatch(line, #"^F\s*(\w+)")) // simple type
CG.SimpleType(Regex.Split(line, #"^F\s*(\w+)")[1], Regex.Split(line, #"^F\s*(\w+)")[2]);
else
Console.WriteLine("Invalid line " + line);
}
}
}
// Code Generator for C#
public class CSharpCode
{
public void BlankLine() { Console.WriteLine(); }
public void Comment(string comment) { Console.WriteLine("//" + comment); }
public void StartMsg(string name) { Console.WriteLine("public struct " + name + "{"); }
public void EndMsg() { Console.WriteLine("}"); }
public void SimpleType(string name, string type)
{
if(type.Contains("char["))
type = "string";
Console.WriteLine(string.Format("\t{0} {1};", type.Trim(), name));
}
}
I'm developing a little C# application for the fun. I love this language but something disturb me ...
Is there any way to do a #define (C mode) or a symbol (ruby mode).
The ruby symbol is quite useful. It's just some name preceded by a ":" (example ":guy") every symbol is unique and can be use any where in the code.
In my case I'd like to send a flag (connect or disconnect) to a function.
What is the most elegant C# way to do that ?
Here is what i'd like to do :
BgWorker.RunWorkersAsync(:connect)
//...
private void BgWorker_DoWork(object sender, DoWorkEventArgs e)
{
if (e.Arguement == :connect)
//Do the job
}
At this point the my favorite answer is the enum solution ;)
In your case, sending a flag can be done by using an enum...
public enum Message
{
Connect,
Disconnect
}
public void Action(Message msg)
{
switch(msg)
{
case Message.Connect:
//do connect here
break;
case Message.Disconnect:
//disconnect
break;
default:
//Fail!
break;
}
}
You could use a string constant:
public const string Guy = "guy";
In fact strings in .NET are special. If you declare two string variable with the same value they actually point to the same object:
string a = "guy";
string b = "guy";
Console.WriteLine(object.ReferenceEquals(a, b)); // prints True
C# doesn't support C-style macros, although it does still have #define. For their reasoning on this take a look at the csharp FAQ blog on msdn.
If your flag is for conditional compilation purposes, then you can still do this:
#define MY_FLAG
#if MY_FLAG
//do something
#endif
But if not, then what you're describing is a configuration option and should perhaps be stored in a class variable or config file instead of a macro.
Similar to #Darin but I often create a Defs class in my project to put all such constants so there is an easy way to access them from anywhere.
class Program
{
static void Main(string[] args)
{
string s = Defs.pi;
}
}
class Defs
{
public const int Val = 5;
public const string pi = "3.1459";
}
I fixed all the problems described here (and one additional), and posted the modified
csharp-mode.el (v0.7.1) at emacswiki
The csharp-mode I use is almost really good.
It works for most things, but has a few problems:
#if / #endif tags break indentation, but only within the scope of a method.
attributes applied to fields within a struct, break indentation. (sometimes, see example)
within classes that implement interfaces, the indenting is broken. from that point forward.
Literal strings (prefixed with #) do not fontify correctly, and in fact break fontification from that point forward in the source file, if the last character in the literal string is a slash.
I think there are some other problems, too.
I'm not a mode writer.
Has anyone got improvements on that mode?
anyone want to volunteer to fix these few things?
example code
using System;
using System.IO;
using System.Linq;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Xml.Serialization;
namespace Cheeso.Says.TreyIsTheBest
{
public class Class1
{
private void Method1()
{
// Problem 1: the following if / endif pair causes indenting to break.
// This occurs only within the scope of a method. If the #if/#endif is
// outside of a method, then the indenting does not break.
#if DIAGS
// this first line of code within the conditional scope
// is indented
String StringNumber1;
// the second line of code within the conditional scope
// is un-indented
public String StringNumber2;
#endif
// The endif is where I expect it to be, I guess.
// It's in-line with the matched #if. But the comments here
// are weirdly indented still further. ??
}
// The prior close-curly is indented 2 units more than I would expect.
}
// the close-curly for the class is indented correctly.
// ==================================================================
// ------------------------------------------------------------------
[StructLayout(LayoutKind.Sequential,
CharSet = CharSet.Unicode)]
public struct Class2
{
// Problem 2: when there is an attribute applied to a field
// within a struct, and the attribute include a newline, then
// the field indents strangely. See also "Note 1", and "Note 2"
// below.
[MarshalAs(UnmanagedType.ByValArray,
SizeConst = 128)]
public int Value1;
// Note 1: this indents fine.
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 128)]
public int Value2;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public class Class3
{
public short PrintNameLength;
[MarshalAs(UnmanagedType.ByValArray,
SizeConst = 128)]
// Note 2: this indents just fine
public int Value1;
}
// ==================================================================
// ------------------------------------------------------------------
// Linq Syntax is not a problem as I had originally thought
public class Class4
{
#region eee
#endregion
private void Method1()
{
var files = Directory.GetFiles("Something");
var selection = from f in files
where System.IO.Path.GetFileName(f).StartsWith("C")
select f;
foreach (var e in selection)
Console.WriteLine(e);
}
}
// ==================================================================
// ------------------------------------------------------------------
public interface IGuess { }
public class Class5 : IGuess
{
// Problem 3: When a #region tag is used inside a class that
// implements an interface (or derives from a class) the line
// following the region tag gets indented one extra unit.
#region utility
private static System.Random rnd= new System.Random();
private string FigureCategory()
{
return "unknown";
}
#endregion
// You can also see artifacts of the same confusion in
// methods that have multiple attributes. Again, this only
// occurs when the containing class implements a particular
// interface or derives from a parent class.
[System.Web.Services.WebMethodAttribute()]
[return: System.Xml.Serialization.XmlElementAttribute("getContainerObjectsReturn")]
public String Method1()
{
return "Hello.";
}
}
// ==================================================================
// ------------------------------------------------------------------
public class Pippo
{
// Problem 4: when the final char in an "escaped" string literal is a
// slash, indenting and fontification breaks.
List<string> directories = new List<string> {
#"C:\Temp\sub1\",
// The emacs parser thinks the string has not ended.
// This comment is fontified and indented as if it is in
// the middle of a string literal.
#"C:\Temp\sub2\",
// Because we have another \" at the end of a string,
// emacs now thinks we're "out" of the string literal.
// This comment is now indented and fontified correctly.
#"C:\Home\"
// A third \", and now emacs thinks we're back inside the string literal.
// The rest of the code will be treated as if it were inside the string literal.
};
protected void Page_Load(object sender, EventArgs e)
{
Console.WriteLine("Hello {0}", "world");
}
}
}
This snippet of advice appears to fixes the first half of the indentation problem #1. I'm hoping it won't cause problems elsewhere. It just looks for the condition that is causing the bad indentation (syntax statement-cont and #if or #endif (well, just #)) at the beginning of that) and returns the syntax deduced from before that point. Looks good to me, but I'm not the judge here.
(defvar csharp-mode-syntax-table-no-special-slash
(let ((res (copy-syntax-table csharp-mode-syntax-table)))
(modify-syntax-entry ?\\ "w" res)
res)
"same as regular csharp-mode-syntax-table, only \\ is not an escape char")
(defadvice c-guess-basic-syntax (after c-guess-basic-syntax-csharp-hack activate)
"following an #if/#endif, indentation gets screwey, fix it"
(let ((res ad-return-value))
(save-excursion
(save-match-data
(cond ((and (eq major-mode 'csharp-mode)
(eq 'statement-cont (caar res))
(progn
(goto-char (cadar res))
(looking-at "#")))
;; when following a #if, try for a redo
(goto-char (cadar res))
(setq ad-return-value (c-guess-basic-syntax)))
((and (eq major-mode 'csharp-mode)
(eq 'string (caar res)))
;; inside a string
;; check to see if it is a literal
;; and if so, redo with modified syntax table
(let ((p (point))
(extent (c-literal-limits)))
(when extent
(goto-char (- (car extent) 1))
(when (looking-at "#\"")
;; yup, a string literal
(with-syntax-table csharp-mode-syntax-table-no-special-slash
(goto-char p)
(setq ad-return-value (c-guess-basic-syntax))))))))))))
The close curly brace is still indented improperly. I think folks who maintain the indentation code would know how to make changes. It's beyond the scope of my understanding. There are 104 different "cases" of indentation managed by the cc-engine...
(Same with indentation for Problems 2 & 3, they all are deemed to be a part of 'statement-cont syntax). To see the what the cc-engine thinks the syntax under the current point is, do: C-c C-s.
And regarding Problem 4, the literal string, the above seems to properly indent the literal string, but fontification is still broken.
I am trying to understand how this piece of self-replicating code works (found here), but the problem is I can't get it to run as-is:
class c {
static void Main(){
string s = "class c{{static void Main(){{string s={0}{10};System.Console.Write(s,(char)34,s);}}}}";
System.Console.Write(s,(char)34,s); //<<-- exception on this line
}
}
It's throwing an exception on writeline: Index (zero based) must be greater than or equal to zero and less than the size of the argument list.
Can someone help - in particular about the formatting option {0}{10}?
I got it working like this (see below) but it's longer than the original - I am curious how the original could have worked as-is in the 1st place:
class c {
static void Main(){
string s = "class c{{static void Main(){{string s={0}{1}{2};System.Console.Write(s,(char)34,s,(char)34);}}}}";
System.Console.Write(s,(char)34,s,(char)34);
}
}
I think there is a pair of braces missing - instead of {10} it should read {1}{0}.
class c {
static void Main(){
string s = "class c{{static void Main(){{string s={0}{1}{0};System.Console.Write(s,(char)34,s);}}}}";
System.Console.Write(s,(char)34,s); //<<-- exception on this line
}
}
Could the original work with?
s={0}{1}{0}
I believe that the original was supposed to look like this:
class c {
static void Main() {
string s = "class c{{static void Main(){{string s={0}{1}{0};System.Console.Write(s,(char)34,s);}}}}";
System.Console.Write(s, (char)34, s);
}
}
I.e. the {0}{10} should just be changed to {0}{1}{0}.
The {0} in the format string is used to put the quotation marks before and after the string.