I have a function in C# that finds the name of a function in a source file such as
function void MyFunc
I'm trying to create a substring that starts after "void " and I need to find the length of the name of the function. There will always be a space or a newline after the function name.
module MyApplication
[EntryPoint]
function void main
write("a string")
endfunction
endmodule
You can use LastIndexOf to find the last space, and grab the part of the string following to get the function name. Then use the Length property to get the length of the code:
var s = "function void MyFunc "; // example string
var s2 = s.Trim(); // remove any extra spaces at the end
var funcName = s2.Substring(s2.LastIndexOf(' ') + 1); // 'MyFunc'
var length = funcName.Length; // 6
Demo: http://www.ideone.com/64IYz
I assume that the function name might have other stuff after it, like a parameter list.
What you want to do is look for the word "void", go past it, find the first non-space character (which is the beginning of the function name), and then go to the next space or end of line.
You can use:
const string LookFor = "void "; // note space at end.
string GetFunctionName(string line)
{
int voidPos = line.IndexOf(LookFor);
if (voidPos == -1)
return null;
int functionStart = voidPos + LookFor.Length;
int spacePos = line.IndexOf(' ', functionStart);
if (spacePos == -1)
spacePos = line.Length;
return line.Substring(functionStart, spacePos - functionStart);
}
That's "crying for using regex". Try this:
Regex regex = new Regex("(function void ){1,1}(?<functionName>^\w*)");
Sprache can do this, but you'd need to write a grammar for the whole file, as it doesn't implement "searching" for a match.
Something along these lines would parse just the function declaration - as noted above, to make your scenario work you need to add rules for modules and so on.
var identifier = (from first in Parse.Letter
from rest in Parse.LetterOrDigit.Many().Text()
select first + rest).Token();
var returnType = Parse.String("void").Or(Parse.String("int")).Token();
var functionKeyword = Parse.String("function").Token();
var endFunctionKeyword = Parse.String("endfunction").Token();
var function = from fk in functionKeyword
from rt in returnType
from functionName in identifier
from body in Parse.AnyChar.Until(endFunctionKeyword)
select functionName;
var name = function.Parse("function void main write(\"a string\") endfunction");
The variable name above will contain the string "main" (unless I've made some typos :))
Sprache is a bit more powerful than regular expressions, but doesn't require any special build-time processing. There are some tutorials on this approach linked from the Sprache homepage.
Related
I have this code:
string firstTag = "Forums2008/forumPage.aspx?forumId=";
string endTag = "</a>";
index = forums.IndexOf(firstTag, index1);
if (index == -1)
continue;
var secondIndex = forums.IndexOf(endTag, index);
result = forums.Substring(index + firstTag.Length + 12, secondIndex - (index + firstTag.Length - 50));
The string i want to extract from is for example:
הנקה
What i want to get is the word after the title only this: הנקה
And the second problem is that when i'm extracting it i see instead hebrew some gibrish like this: ������
One powerful way to do this is to use Regular Expressions instead of trying to find a starting position and use a substring. Try out this code, and you'll see that it extracts the anchor tag's title:
var input = "הנקה";
var expression = new System.Text.RegularExpressions.Regex(#"title=\""([^\""]+)\""");
var match = expression.Match(input);
if (match.Success) {
Console.WriteLine(match.Groups[1]);
}
else {
Console.WriteLine("not found");
}
And for the curious, here is a version in JavaScript:
var input = 'הנקה';
var expression = new RegExp('title=\"([^\"]+)\"');
var results = expression.exec(input);
if (results) {
document.write(results[1]);
}
else {
document.write("not found");
}
Okay here is the solution using String.Substring() String.Split() and String.IndexOf()
String str = "הנקה"; // <== Assume this is passing string. Yes unusual scape sequence are added
int splitStart = str.IndexOf("title="); // < Where to start splitting
int splitEnd = str.LastIndexOf("</a>"); // < = Where to end
/* What we try to extract is this : title="הנקה">הנקה
* (Given without escape sequence)
*/
String extracted = str.Substring(splitStart, splitEnd - splitStart); // <=Extracting required portion
String[] splitted = extracted.Split('"'); // < = Now split with "
Console.WriteLine(splitted[1]); // <= Try to Out but yes will produce ???? But put a breakpoint here and check the values in split array
Now the problem, here you can see that i have to use escape sequence in an unusual way. You may ignore that since you are simply passing the scanning string.
And this actually works, but you cannot visualize it with the provided Console.WriteLine(splitted[1]);
But if you put a break point and check the extracted split array you can see that text are extracted. you can confirm it with following screenshot
I am trying to process a report from a system which gives me the following code
000=[GEN] OK {Q=1 M=1 B=002 I=3e5e65656-e5dd-45678-b785-a05656569e}
I need to extract the values between the curly brackets {} and save them in to variables. I assume I will need to do this using regex or similar? I've really no idea where to start!! I'm using c# asp.net 4.
I need the following variables
param1 = 000
param2 = GEN
param3 = OK
param4 = 1 //Q
param5 = 1 //M
param6 = 002 //B
param7 = 3e5e65656-e5dd-45678-b785-a05656569e //I
I will name the params based on what they actually mean. Can anyone please help me here? I have tried to split based on spaces, but I get the other garbage with it!
Thanks for any pointers/help!
If the format is pretty constant, you can use .NET string processing methods to pull out the values, something along the lines of
string line =
"000=[GEN] OK {Q=1 M=1 B=002 I=3e5e65656-e5dd-45678-b785-a05656569e}";
int start = line.IndexOf('{');
int end = line.IndexOf('}');
string variablePart = line.Substring(start + 1, end - start);
string[] variables = variablePart.Split(' ');
foreach (string variable in variables)
{
string[] parts = variable.Split('=');
// parts[0] holds the variable name, parts[1] holds the value
}
Wrote this off the top of my head, so there may be an off-by-one error somewhere. Also, it would be advisable to add error checking e.g. to make sure the input string has both a { and a }.
I would suggest a regular expression for this type of work.
var objRegex = new System.Text.RegularExpressions.Regex(#"^(\d+)=\[([A-Z]+)\] ([A-Z]+) \{Q=(\d+) M=(\d+) B=(\d+) I=([a-z0-9\-]+)\}$");
var objMatch = objRegex.Match("000=[GEN] OK {Q=1 M=1 B=002 I=3e5e65656-e5dd-45678-b785-a05656569e}");
if (objMatch.Success)
{
Console.WriteLine(objMatch.Groups[1].ToString());
Console.WriteLine(objMatch.Groups[2].ToString());
Console.WriteLine(objMatch.Groups[3].ToString());
Console.WriteLine(objMatch.Groups[4].ToString());
Console.WriteLine(objMatch.Groups[5].ToString());
Console.WriteLine(objMatch.Groups[6].ToString());
Console.WriteLine(objMatch.Groups[7].ToString());
}
I've just tested this out and it works well for me.
Use a regular expression.
Quick and dirty attempt:
(?<ID1>[0-9]*)=\[(?<GEN>[a-zA-Z]*)\] OK {Q=(?<Q>[0-9]*) M=(?<M>[0-9]*) B=(?<B>[0-9]*) I=(?<I>[a-zA-Z0-9\-]*)}
This will generate named groups called ID1, GEN, Q, M, B and I.
Check out the MSDN docs for details on using Regular Expressions in C#.
You can use Regex Hero for quick C# regex testing.
You can use String.Split
string[] parts = s.Split(new string[] {"=[", "] ", " {Q=", " M=", " B=", " I=", "}"},
StringSplitOptions.None);
This solution breaks up your report code into segments and stores the desired values into an array.
The regular expression matches one report code segment at a time and stores the appropriate values in the "Parsed Report Code Array".
As your example implied, the first two code segments are treated differently than the ones after that. I made the assumption that it is always the first two segments that are processed differently.
private static string[] ParseReportCode(string reportCode) {
const int FIRST_VALUE_ONLY_SEGMENT = 3;
const int GRP_SEGMENT_NAME = 1;
const int GRP_SEGMENT_VALUE = 2;
Regex reportCodeSegmentPattern = new Regex(#"\s*([^\}\{=\s]+)(?:=\[?([^\s\]\}]+)\]?)?");
Match matchReportCodeSegment = reportCodeSegmentPattern.Match(reportCode);
List<string> parsedCodeSegmentElements = new List<string>();
int segmentCount = 0;
while (matchReportCodeSegment.Success) {
if (++segmentCount < FIRST_VALUE_ONLY_SEGMENT) {
string segmentName = matchReportCodeSegment.Groups[GRP_SEGMENT_NAME].Value;
parsedCodeSegmentElements.Add(segmentName);
}
string segmentValue = matchReportCodeSegment.Groups[GRP_SEGMENT_VALUE].Value;
if (segmentValue.Length > 0) parsedCodeSegmentElements.Add(segmentValue);
matchReportCodeSegment = matchReportCodeSegment.NextMatch();
}
return parsedCodeSegmentElements.ToArray();
}
I want to replace a charecter in a string with a string in c#.
I have tried the following,
Here in the following program, i want replace set of charecters between charecters ':' and first occurance of '-' with some others charecters.
I could able to extract the set of charecters between ':' and first occurance of '-'.
Can any one say how to insert these back in the source string.
string source= "tcm:7-426-8";
string target= "tcm:10-15-2";
int fistunderscore = target.IndexOf("-");
string temp = target.Substring(4, fistunderscore-4);
Response.Write("<BR>"+"temp1:" + temp + "<BR>");
Examples:
source: "tcm:7-426-8" or "tcm:100-426-8" or "tcm:10-426-8"
Target: "tcm:10-15-2" or "tcm:5-15-2" or "tcm:100-15-2"
output: "tcm:10-426-8" or "tcm:5-426-8" or "tcm:100-426-8"
In a nutshell, I want to replace the set of charectes between ':' and '-'(firstoccurance) and the charecters extracetd from the same sort of string.
Can any help how it can be done.
Thank you.
If you want to replace the first ":Number-" from the source with the content from target, you can use the following regex.
var pattern1 = New Regex(":\d{1,3}-{1}");
if(pattern1.IsMatch(source) && pattern1.IsMatch(target))
{
var source = "tcm:7-426-8";
var target = "tcm:10-15-2";
var res = pattern1.Replace(source, pattern1.Match(target).Value);
// "tcm:10-426-8"
}
Edit: To not have your string replaced with something empty, add an if-clause before the actualy replacing.
Try a regex solution - first this method, takes the source and target strings, and performs a regex replace on the first, targetting the first numbers after the 'tcm', which must be anchored to the start of the string. In the MatchEvaluator it executes the same regex again, but on the target string.
static Regex rx = new Regex("(?<=^tcm:)[0-9]+", RegexOptions.Compiled);
public string ReplaceOneWith(string source, string target)
{
return rx.Replace(source, new MatchEvaluator((Match m) =>
{
var targetMatch = rx.Match(target);
if (targetMatch.Success)
return targetMatch.Value;
return m.Value; //don't replace if no match
}));
}
Note that no replacement is performed if the regex doesn't return a match on the target string.
Now run this test (probably need to copy the above into the test class):
[TestMethod]
public void SO9973554()
{
Assert.AreEqual("tcm:10-426-8", ReplaceOneWith("tcm:7-426-8", "tcm:10-15-2"));
Assert.AreEqual("tcm:5-426-8", ReplaceOneWith("tcm:100-426-8", "tcm:5-15-2"));
Assert.AreEqual("tcm:100-426-8", ReplaceOneWith("tcm:10-426-8", "tcm:100-15-2"));
}
I'm not clear on the logic used to decide which bit from which string is used, but still, you should use Split(), rather than mucking about with string offsets:
(note that the Remove(0,4) is there to remove the tcm: prefix)
string[] source = "tcm:90-2-10".Remove(0,4).Split('-');
string[] target = "tcm:42-23-17".Remove(0,4).Split('-');
Now you have the numbers from both source and target in easy-to-access arrays, so you can build the new string any way you want:
string output = string.Format("tcm:{0}-{1}-{2}", source[0], target[1], source[2]);
Heres without regex
string source = "tcm:7-426-8";
string target = "tcm:10-15-2";
int targetBeginning = target.IndexOf("-");
int sourceBeginning = source.IndexOf("-");
string temp = target.Substring(0, targetBeginning);//tcm:10
string result = temp + source.Substring(sourceBeginning, source.Length-sourceBeginning); //tcm:10 + -426-8
I am reading from history, and I want that when i come across a google query, I can extract the query string. I am not using request or httputility since i am simply parsing a string. however, when i come across URLs like this, my program fails to parse it properly:
http://www.google.com.mt/search?client=firefox-a&rls=org.mozilla%3Aen-US%3Aofficial&channel=s&hl=mt&source=hp&biw=986&bih=663&q=hotmail&meta=&btnG=Fittex+bil-Google
what i was trying to do is get the index of q= and the index of & and take the words in between but in this case the index of & will be smaller than q= and it will give me errors.
any suggestions?
thanks for your answers, all seem good :) p.s. i couldn't use httputility, not I don't want to. when i add a reference to system.web, httputility isn't included! it's only included in an asp.net application. Thanks again
It's not clear why you don't want to use HttpUtility. You could always add a reference to System.Web and use it:
var parsedQuery = HttpUtility.ParseQueryString(input);
Console.WriteLine(parsedQuery["q"]);
If that's not an option then perhaps this approach will help:
var query = input.Split('&')
.Single(s => s.StartsWith("q="))
.Substring(2);
Console.WriteLine(query);
It splits on & and looks for the single split result that begins with "q=" and takes the substring at position 2 to return everything after the = sign. The assumption is that there will be a single match, which seems reasonable for this case, otherwise an exception will be thrown. If that's not the case then replace Single with Where, loop over the results and perform the same substring operation in the loop.
EDIT: to cover the scenario mentioned in the comments this updated version can be used:
int index = input.IndexOf('?');
var query = input.Substring(index + 1)
.Split('&')
.SingleOrDefault(s => s.StartsWith("q="));
if (query != null)
Console.WriteLine(query.Substring(2));
If you don't want to use System.Web.HttpUtility (thus be able to use the client profile), you can still use Mono HttpUtility.cs which is only an independent .cs file that you can embed in your application. Then you can simply use the ParseQueryString method inside the class to parse the query string properly.
here is the solution -
string GetQueryString(string url, string key)
{
string query_string = string.Empty;
var uri = new Uri(url);
var newQueryString = HttpUtility.ParseQueryString(uri.Query);
query_string = newQueryString[key].ToString();
return query_string;
}
Why don't you create a code which returns the string from the q= onwards till the next &?
For example:
string s = historyString.Substring(url.IndexOf("q="));
int newIndex = s.IndexOf("&");
string newString = s.Substring(0, newIndex);
Cheers
Use the tools available:
String UrlStr = "http://www.google.com.mt/search?client=firefox-a&rls=org.mozilla%3Aen-US%3Aofficial&channel=s&hl=mt&source=hp&biw=986&bih=663&q=hotmail&meta=&btnG=Fittex+bil-Google";
NameValueCollection Items = HttpUtility.ParseQueryString(UrlStr);
String QValue = Items["q"];
If you really need to do the parsing yourself, and are only interested in the value for 'q' then the following would work:
string url = #"http://www.google.com.mt/search?" +
"client=firefoxa&rls=org.mozilla%3Aen-" +
"US%3Aofficial&channel=s&hl=mt&source=hp&" +
"biw=986&bih=663&q=hotmail&meta=&btnG=Fittex+bil-Google";
int question = url.IndexOf("?");
if(question>-1)
{
int qindex = url.IndexOf("q=", question);
if (qindex > -1)
{
int ampersand = url.IndexOf('&', qindex);
string token = null;
if (ampersand > -1)
token = url.Substring(qindex+2, ampersand - qindex - 2);
else
token = url.Substring(qindex+2);
Console.WriteLine(token);
}
}
But do try to look at using a proper URL parser, it will save you a lot of hassle in the future.
(amended this question to include a check for the '?' token, and support 'q' values at the end of the query string (without the '&' at the end) )
And that's why you should use Uri and HttpUtility.ParseQueryString.
HttpUtility is fine for the .Net Framework. However that class is not available for WinRT apps. If you want to get the parameters from a url in a Windows Store App you need to use WwwFromUrlDecoder. You create an object from this class with the query string you want to get the parameters from, the object has an enumerator and supports also lambda expressions.
Here's an example
var stringUrl = "http://localhost/?name=Jonathan&lastName=Morales";
var decoder = new WwwFormUrlDecoder(stringUrl);
//Using GetFirstByName method
string nameValue = decoder.GetFirstByName("name");
//nameValue has "Jonathan"
//Using Lambda Expressions
var parameter = decoder.FirstOrDefault(p => p.Name.Contains("last")); //IWwwFormUrlDecoderEntry variable type
string parameterName = parameter.Name; //lastName
string parameterValue = parameter.Value; //Morales
You can also see http://www.dzhang.com/blog/2012/08/21/parsing-uri-query-strings-in-windows-8-metro-style-apps
I have a richtextbox that its text is a concatenation of some words from specific table. (table columns are 'word','translate' and 'id')
I need that when a user hover on each word, the related translate is showed in word's tooltip.
(something like google translate but in windows form application.)
Can somebody point me towards a solution?
using Web-browser Control and Injecting JavaScript solved my problem. ;)
This will do the trick...
private void richTextBox1_MouseMove(object sender, MouseEventArgs e)
{
// whitespace definition
char[] whitespace = new char[] { ' ', '\r', '\n', '\t' };
int charPosition = this.richTextBox1.GetCharIndexFromPosition(e.Location);
string fullText = this.richTextBox1.Text;
// if we are on whitespace, exit
if (whitespace.Contains(fullText[charPosition]))
{
return;
}
// find a whitespace towards the start of the text
int firstWhiteSpace = charPosition;
while (firstWhiteSpace > 0
&& firstWhiteSpace < fullText.Length
&& !whitespace.Contains(fullText[firstWhiteSpace]))
{
firstWhiteSpace--;
}
if (firstWhiteSpace!=0)
firstWhiteSpace++;
// find the next whitespace
int lastWhiteSpace = fullText.IndexOfAny(whitespace, charPosition);
if (lastWhiteSpace == -1)
lastWhiteSpace = fullText.Length;
// substring the word out of the flat text
string word = fullText.Substring(
firstWhiteSpace,
lastWhiteSpace - firstWhiteSpace);
// show the result
label1.Text = String.Format("pos:{0} fsp:{1}, lsp:{2}, len:{3}, word:{4}",
charPosition,
firstWhiteSpace,
lastWhiteSpace,
fullText.Length, word);
}
I am not fluent in C#, and I am also brand new to this forum. However, it looks to me like if you were to supplement the code rene posted with a function which queries your Translation table and returns the translation text, you would then have this (forgive my pseudo-code butchery - I am very fluent in vb.net, gonna learn the C# syntax soon):
Private String TranslatedWord(ByVal SelectedWord String)
{
//Use ADO and SQL to retrieve the Translation(s) associated with the submitted Word
// A string SQL Statement (the GROUP ON is in case there are multiple instances of the same word, with different translations (synonyms). THis SQL Should return a a single record for each possible translation of the submitted word (more than one result possible):
Dim SQL as String = _
"SELECT tr.ID, tr.Translate " & _
"FROM MyTranslationTable AS tr " & _
"WHERE tr.Word LIKE #Word"
//Since I could be ALL DAY struggling to write the C# code for this, I will just step through it in "pseudocode":
// 1. Execute the SQL using ADO.Net, set up the #Word Param in your command, and return a sqlDataReader
// 2. Iterate through the returned records, and append the Translation results to a System.Text.Stringbuilder object. Delimit each returned value with a semi-colon (or your delimiter of choice).
// Return the Stringbuilder.ToString property as the result of this function;
}
Then change the last part of rene's code ("//Show the result") as follows (suitable corrected for my horrible C# problem!):
private void richTextBox1_MouseMove(object sender, MouseEventArgs e)
{
// whitespace definition
char[] whitespace = new char[] { ' ', '\r', '\n', '\t' };
int charPosition = this.richTextBox1.GetCharIndexFromPosition(e.Location);
string fullText = this.richTextBox1.Text;
// if we are on whitespace, exit
if (whitespace.Contains(fullText[charPosition]))
{
return;
}
// find a whitespace towards the start of the text
int firstWhiteSpace = charPosition;
while (firstWhiteSpace > 0
&& firstWhiteSpace < fullText.Length
&& !whitespace.Contains(fullText[firstWhiteSpace]))
{
firstWhiteSpace--;
}
if (firstWhiteSpace!=0)
firstWhiteSpace++;
// find the next whitespace
int lastWhiteSpace = fullText.IndexOfAny(whitespace, charPosition);
if (lastWhiteSpace == -1)
lastWhiteSpace = fullText.Length;
// substring the word out of the flat text
string word = fullText.Substring(
firstWhiteSpace,
lastWhiteSpace - firstWhiteSpace);
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//My CHanges start here, and will likely require
// some tweaking . . .
//Use the function I have poorly described above to retreive the
//translation(s) for the current Word:
string TRANSLATION = TranslatedWord(word);
// show the result
//Since there are so many minor but important differences between C# and VB, I am not going to attempt
//to account for them. Essentially, display the translated word instead of the word over which the mouse is hovering:
label1.Text = String.Format("pos:{0} fsp:{1}, lsp:{2}, len:{3}, word:{4}",
charPosition,
firstWhiteSpace,
lastWhiteSpace,
fullText.Length, TRANSLATION);
}
If it would be helpful, I could bust out the vb.net code for this fairly quickly, but I wasn't going to do that unless it would be helpful.
Hope that's helpful. I am going to have to work a little at learning C#, and at improving my understanding of posting in this forum! Getting the code to look right is proving a challenge . . .