I had to take over a c# project. The guy who developed the software in the first place was deeply in love with #region because he wrapped everything with regions.
It makes me almost crazy and I was looking for a tool or addon to remove all #region from the project. Is there something around?
Just use Visual Studio's built-in "Find and Replace" (or "Replace in Files", which you can open by pressing Ctrl + Shift + H).
To remove #region, you'll need to enable Regular Expression matching; in the "Replace In Files" dialog, check "Use: Regular Expressions". Then, use the following pattern: "\#region .*\n", replacing matches with "" (the empty string).
To remove #endregion, do the same, but use "\#endregion .*\n" as your pattern. Regular Expressions might be overkill for #endregion, but it wouldn't hurt (in case the previous developer ever left comments on the same line as an #endregion or something).
Note: Others have posted patterns that should work for you as well, they're slightly different than mine but you get the general idea.
Use one regex ^[ \t]*\#[ \t]*(region|endregion).*\n to find both: region and endregion. After replacing by empty string, the whole line with leading spaces will be removed.
[ \t]* - finds leading spaces
\#[ \t]*(region|endregion) - finds #region or #endregion (and also very rare case with spaces after #)
.*\n - finds everything after #region or #endregion (but in the same line)
EDIT: Answer changed to be compatible with old Visual Studio regex syntax. Was: ^[ \t]*\#(end)?region.*\n (question marks do not work for old syntax)
EDIT 2: Added [ \t]* after # to handle very rare case found by #Volkirith
In Find and Replace use {[#]<region[^]*} for Find what: and replace it with empty string.
#EndRegion is simple enough to replace.
Should you have to cooperate with region lovers (and keep regions untouched ), then I would recommend "I hate #Regions" Visual Studio extension. It makes regions tolerable - all regions are expanded by default and #region directives are rendered with very small font.
For anyone using ReSharper it's just a simple Atr-Enter on the region line. You will then have the option to remove regions in file, in project, or in solution.
More info on JetBrains.
To remove #region with a newline after it, replace following with empty string:
^(?([^\r\n])\s)*\#region\ ([^\r\n])*\r?\n(?([^\r\n])\s)*\r?\n
To replace #endregion with a leading empty line, replace following with an empty string:
^(?([^\r\n])\s)*\r?\n(?([^\r\n])\s)*\#endregion([^\r\n])*\r?\n
How about writing your own program for it, to replace regions with nothing in all *.cs files in basePath recursively ?
(Hint: Careful with reading files as UTF8 if they aren't.)
public static void StripRegions(string fileName, System.Text.RegularExpressions.Regex re)
{
string input = System.IO.File.ReadAllText(fileName, System.Text.Encoding.UTF8);
string output = re.Replace(input, "");
System.IO.File.WriteAllText(fileName, output, System.Text.Encoding.UTF8);
}
public static void StripRegions(string basePath)
{
System.Text.RegularExpressions.Regex re = new System.Text.RegularExpressions.Regex(#"(^[ \t]*\#[ \t]*(region|endregion).*)(\r)?\n", System.Text.RegularExpressions.RegexOptions.Multiline);
foreach (string file in System.IO.Directory.GetFiles(basePath, "*.cs", System.IO.SearchOption.AllDirectories))
{
StripRegions(file, re);
}
}
Usage:
StripRegions(#"C:\sources\TestProject")
You can use the wildcard find/replace:
*\#region *
*\#endregion
And replace with no value. (Note the # needs to be escaped, as visual stuido uses it to match "any number")
Related
I need to create a C#.NET program which will search specific words in a Microsoft Word document and will replace it with another words. For example, in my word file there is a text which is – LeadSoft IT. This “LeadSoft IT” will be replaced by – LeadSoft IT Limited. Now there is a problem which is, at the first time LeadSoft IT will be replaced with LeadSoft IT Limited. But if I run the program again then it will change LeadSoft IT again and in the next time the text will be LeadSoft IT Limited Limited. This is a problem. Can anyone suggest me how to solve this problem with C# code to replace words in word document.
If you already have some script for this, feel free to post it and I'll try and help more.
I'm not sure what functionality you're using to find the text instance, but I would suggest looking into regex, and using something like (LeadSoft IT(?! Limited)).
Regex: https://regexr.com/
A good regex tester: https://www.regextester.com/109925
Edit: I made a Python script that uses regex to replace the instances:
import re
word_doc = "We like working " \
"here at Leadsoft IT.\n" \
"We are not limited here at " \
"Leadsoft It Limited."
replace_str = "Leadsoft IT Limited"
reg_str = '(Leadsoft IT(?!.?Limited))'
fixed_str = re.sub(reg_str, replace_str, word_doc, flags=re.IGNORECASE)
print(fixed_str)
# Prints:
# We like working here at Leadsoft IT Limited.
# We are not limited here at Leadsoft It Limited.
Edit 2: Code re-created in C#: https://gist.github.com/Zylvian/47ecd6d1953b8d8c3900dc30645efe98
The regex checks the entire string for instances where Leadsoft IT is NOT followed by Limited, and for all those instances, replaces Leadsoft IT with Leadsoft IT Limited.
The regex uses what's called a "negative lookahead (?!)" which makes sure that the string to the left is not followed by the string to the right. Feel free to edit the regex how you see fit, but be aware that the matching is very strong.
If you want to understand the regex string better, feel free to copy it into https://www.regextester.com/.
Let me know if that helps!
Simplistically, you can just run another replace to fix the problem you cause:
s = s.Replace("LeadSoft IT", "LeadSoft IT Limited").Replace("LeadSoft IT Limited Limited", "LeadSoft IT Limited");
If you're after a more generic fixing of this that doesn't hard code the problem string, consider examining whether the string you find is inside the string you replace with, which will mean the problem occurs. This means you need to run a second replacement on the document that finds the result of running the replacement on the replacement
var find = "LeadSoft IT";
var repl = "LeadSoft IT Limited";
var result = document.Replace(find, repl);
var problemWillOccur = repl.Contains(find);
if(problemWillOccur){
var fixProblemByFinding = repl.Replace(find, repl); //is "LeadSoft IT Limited Limited"
result = result.Replace(fixProblemByFinding, repl);
}
You may be interested how I solve this problem.
At first, I was using NPOI but it was making a mess with document, so I discovered that a DOCX file is simply a ZIP Archive with XMLs.
https://github.com/kubala156/DociFlow/blob/main/DociFlow.Lib/Word/SeekAndReplace.cs
Usage:
var vars = Dictionary<string, string>()
{
{ "testtag", "Test tag value" }
}
using (var doci = new DociFlow.Lib.Word.SeekAndReplace())
{
// test.docx contains text with tag "{{testtag}}" it will be replaced with "Test tag value"
doci.Open("test.docx");
doci.FindAndReplace(vars, "{{", "}}");
}
NPOI 2.5.4 provides ReplaceText method to help you replace placeholders in a Word file.
Here is an example.
https://github.com/nissl-lab/npoi-examples/blob/main/xwpf/ReplaceTexts/Program.cs
Does someone have a script or snippet for Visual Studio that automatically removes comment headers for functions or classes?
I want to remove comments like.
/// <summary>
///
/// </summary>
Actually anything that removes comments starting with /// would really help. We have projects with massive amount of GhostDoc comment that really just hides the code and we are not using the document output. It is a tedious work for us to remove theese comments.
Open Quick Replace (CTRL + H) in Visual Studio and replace :b+///.*\n with an empty string (ensure you set Use to Regular expressions). This should allow you to get rid of the comments in the specified scope.
You can use this Regex \/\/\/.*<summary>.*<\/summary>, with these options gms, to match the string. You can replace that with nothing. This can be done in Notepad++ or Visual Studio.
Here is a Regex 101 to prove it.
You can use Python (with regexps, if you wish):
#! /usr/bin/python
import sys
if len(sys.argv) < 2:
print( "Usage: removelines <source-file>" )
exit(0)
InFileName = sys.argv[1]
Out = open( InFileName + ".out", "w" );
for Line in open( InFileName ).readlines():
if Line.lstrip().find( "///" ) == 0:
print( "Skipping line", Line )
continue
Out.write( Line )
You could use find and replace in files in Notepad++ (or any other advanced text editor) using regex.
You can just do find and replace with an empty string in visual studio. You already have the strings you want to get rid of. You could also parse the code files as text and remove any line that starts with a comment character.
I am reading a C# source file.
When I encounter a string, I want to get it's value.
For instance, in the following example:
public class MyClass
{
public MyClass()
{
string fileName = "C:\\Temp\\A Weird\"FileName";
}
}
I would like to retrieve
C:\Temp\A Weird"FileName
Is there an existing procedure to do that?
Coding a solution with all the possible cases should be quite tricky (#, escape sequences. ...).
I am convinced such procedure exists...
I would like to have the dual function too (to inject a string into a C# source file)
Thanks in advance.
Philippe
P.S:
I gave an example with a filename, but I look for a solution working for all kinds of strings.
I'm pretty sure you can use CodeDOM to read a C# code file and parse its elements. It generates a code tree, and then you can look for nodes representing strings.
http://www.codeproject.com/Articles/2502/C-CodeDOM-parser
Other CodeDom parsers:
http://www.codeproject.com/Articles/14383/An-Expression-Parser-for-CodeDom
NRefactory: https://github.com/icsharpcode/NRefactory and http://www.codeproject.com/Articles/408663/Using-NRefactory-for-analyzing-Csharp-code
There is a way of extracting these strings using a regular expression:
("(\\"|[^"])*")
This particular one works on your simple example and gives the filename (complete with leading and trailing quote characters); whether it would work on more complex ones I can't easily tell unfortunately.
For clarity, (\\"|[^"]) matches any character apart from ", except where it has a leading \ character.
Just use ".*" Regex to match all string values, then remove trailing inverted commas and unescape it.
this will allow \" and "" characters inside your string
so both "C:\\Temp\\A Weird\"FileName" and "Hello ""World""" will match
Have been studying a sample source code and I can't understand this part, what is this piece of code doing? Mostly the RegEx part...
in the parameters used, "code" is a string, it is C# source code we are passing in.
Match m = null;
if ((m = Regex.Match(code, "(?ims)^[/']{2}REFDLL (?<ref>.+?)$")).Success)
{
foreach (string refDll in m.Groups["ref"].Value.Split(new char[] { ';', ',' }))
{
//2008-06-18 by Jeffrey, remove redundant \r
string mdfyRefDll = refDll.Replace("\r", "").Replace("\n", "");
//trim the ending .dll if exists
if (mdfyRefDll.ToLower().EndsWith(".dll"))
mdfyRefDll = mdfyRefDll.Substring(0, mdfyRefDll.Length - 4);
string lcRefDll = mdfyRefDll.ToLower();
if (lcRefDll == "system.data.linq" || lcRefDll == "system"
|| lcRefDll == "system.xml.linq" || lcRefDll == "system.core")
continue;
cp.ReferencedAssemblies.Add(mdfyRefDll + ".dll");
}
}
I think this image addresses what's going on in the code you posted:
Mini C# Lab's project description is as follows:
A handy tool for simple short C# code running and testing, you can
save time on waiting for Visual Studio startup and avoid creating a
lot of one-time only project files.
It seems like that project is missing documentation, so it's difficult to extrapolate why the author of the code chose that particular way to add referenced DLLs when there is a using directive in there already. Perhaps he did it to avoid conflicts with the using statement.
First, (?ims) is specifying options. i triggers case-insensitivity, m specifies multi-line mode, and s (IIRC) enables the dot-all option, meaning that the wildcard . includes newline characters.
Then, ^ asserts, "The string must begin here, with no preceding characters..." while the $ at the end asserts, "The string must end here, with no following characters."
The [/']{2} matches exactly two of either the slash or single-quote characters, i.e. //, '', /', and '/.
The REFDLL matches exactly what you see.
The (?<ref>.+?) matches all remaining characters (the final question mark is unnecessary), and remember, due to the s option, this includes newline characters. This portion is stored in a match named ref.
In summary, it's trying to match something like
//REFDLL helloworld foobar
and stores "helloworld foobar" in ref.
I have strings in the form: "[user:fred][priority:3]Lorem ipsum dolor sit amet." where the area enclosed in square brackets is a tag (in the format [key:value]). I need to be able to remove a specific tag given it's key with the following extension method:
public static void RemoveTagWithKey(this string message, string tagKey) {
if (message.ContainsTagWithKey(tagKey)) {
var regex = new Regex(#"\[" + tagKey + #":[^\]]");
message = regex.Replace(message , string.Empty);
}
}
public static bool ContainsTagWithKey(this string message, string tagKey) {
return message.Contains(string.Format("[{0}:", tagKey));
}
Only the tag with the specified key should be removed from the string. My regex doesn't work because it's daft. I need help to write it properly. Alternatively, an implementation without regex is welcome.
I know there are much more feature-rich tools out there, but I like the simplicity and cleanliness of Code Architects Regex Tester (aka YART: Yet Another Regex Tester). Shows groups and captures in a tree view, quite fast, very small, open source. It also generates code in C++, VB, and C# and can automatically escape or unescape regexes for these languages. I dump it in my VS tools folder (C:\Program Files\Microsoft Visual Studio 9.0\Common7\Tools) and set a menu item to it in the Tools menu with Tools > External Tools so I can fire it up quickly from inside VS.
Regexes can be really hard to write sometimes and I know it really helps to be able to test the regex and see the results as you go.
(source: dotnet2themax.com)
Another really popular (but not free) option is Regex Buddy.
If you want to do this without a Regex it isn't difficult. You're already searching for a specific tag key, so you can just search for "[" + tagKey, then search from there for the closing "]", and remove everything between those offsets. Something like...
int posStart = message.IndexOf("[" + tagKey + ":");
if(posStart >= 0)
{
int posEnd = message.IndexOf("]", posStart);
if(posEnd > posStart)
{
message = message.Remove(posStart, posEnd - posStart);
}
}
Is that better than a Regex solution? Since you're only looking for a specific key I think it probably is, on the grounds of simplicity. I love Regexes but they're not always the clearest answer.
Edit: Another reason the IndexOf() solution could be seen as better is that it means there is only one rule for finding the start of the tag, whereas the original code uses a Contains() which searches for something like '[tag:' and then uses a regex which uses a slightly different expression to do the substitution / removal. In theory you could have text which matches one criterion but not the other.
Try this instead:
new Regex(#"\[" + tagKey + #":[^\]+]");
The only thing I changed was to add + to the [^\] pattern, meaning that you match one or more characters that are not a backslash.
I think this is the regex you're looking for:
string regex = #"\[" + tag + #":[^\]+]\]";
Also, you don't need to do a separate check to see if there are tags of that type. Just do a regex replace; if there are no matches, the original string is returned.
public static string RemoveTagWithKey(string message, string tagKey) {
string regex = #"\[" + tag + #":[^\]+]\]";
return Regex.Replace(message, regex, string.Empty);
}
You seem to be writing an extension method, but I wrote this as a static utility method to keep things simple.