I am fairly new to c# and am working on a little project but got stuck on this. I have a file that contains some assembly code. I want my program to search this file for a string, actually a value right after my string. One of the strings i am searching for is:
setproperty QName(PackageNamespace(""), "font")
getlocal 4
pushint
My search code is this:
private void searchFile(String searchText)
{
System.IO.StreamReader reader = new System.IO.StreamReader(file);
String text = reader.ReadToEnd();
if (Regex.IsMatch(text, searchText))
{
MessageBox.Show(searchText + " was found in the given file", "Finally!!");
}
else
{
MessageBox.Show("Sorry, but " + searchText + " could not be found in the given file", "No Results");
}
}
//when i click a button//
searchFile(#"setproperty QName(PackageNamespace(""""), ""font"")
getlocal 4
pushint ");
I know that the string is in the file but the result comes up with not found. I don't know if it is the quotes or tabs or both that is causing this.
Here is part of the file:
getlocal 4
pushstring "Verdana"
setproperty QName(PackageNamespace(""), "font")
getlocal 4
pushint 16764170
setproperty QName(PackageNamespace(""), "color")
getlocal 4
pushbyte 12
setproperty QName(PackageNamespace(""), "size")
My second question is how can i get the value of the first int after my search result?
Thanks in advance.
-Leen
You should change your method like this:
private static string searchFile(String searchText)
{
System.IO.StreamReader reader = new System.IO.StreamReader("test.txt");
String text = reader.ReadToEnd();
int poz = text.IndexOf(searchText);
if (poz >= 0)
{
int start = poz + searchText.Length;
int end = text.IndexOf("\n", start);
Console.WriteLine(searchText + " was found in the given file", "Finally!!");
return text.Substring(start, end - start);
}
else
{
Console.WriteLine("Sorry, but " + searchText + " could not be found in the given file", "No Results");
return string.Empty;
}
}
The call:
string val = searchFile("setproperty QName(PackageNamespace(\"\"), \"font\")\r\n\r\n getlocal 4\r\n pushint ");
So I think you may be use to VB.net. C-based languages (like c#) used the backslash character "\" as an escape character.
So in a searching for a double-quote in a string you would need to escape it using \".
I believe what you're looking for is:
searchFile(#"setproperty QName(PackageNamespace(\"\"), \"font\")
getlocal 4
pushint ");
But this isn't really a regular expression, which is what the Regex class is meant for. So I would (well not really, I would clean it up a bit, like not mix my UI and bizlogic) do this:
// Added String as the function type so you can return the matched "Integer" as a string, you could always do a Int32.TryParse(...)
private String searchFile(String file, String searchText)
{
System.IO.StreamReader reader = new System.IO.StreamReader(file);
String text = reader.ReadToEnd();
int32 index = text.IndexOf(searchText);
if (index >= 0) //We could find it at the very beginning
{
MessageBox.Show(searchText + " was found in the given file", "Finally!!");
int32 start = index + searchText.Length;
int32 end = Regex.Match(text, "[\n\r\t]", index).Index; // This will search for whitespace
String value = text.Substring(start, end - start);
// Now you can do something with your value, like...
return value;
}
else
{
MessageBox.Show("Sorry, but " + searchText + " could not be found in the given file", "No Results");
return "";
}
}
Related
So I have a long string containing pointy brackets that I wish to extract text parts from.
string exampleString = "<1>text1</1><27>text27</27><3>text3</3>";
I want to be able to get this
1 = "text1"
27 = "text27"
3 = "text3"
How would I obtain this easily? I haven't been able to come up with a non-hacky way to do it.
Thanks.
Using basic XmlReader and some other tricks to do wrapper to create XML-like data, I would do something like this
string xmlString = "<1>text1</1><27>text27</27><3>text3</3>";
xmlString = "<Root>" + xmlString.Replace("<", "<o").Replace("<o/", "</o") + "</Root>";
string key = "";
List<KeyValuePair<string,string>> kvpList = new List<KeyValuePair<string,string>>(); //assuming the result is in the KVP format
using (XmlReader xmlReader = XmlReader.Create(new StringReader(xmlString))){
bool firstElement = true;
while (xmlReader.Read()) {
if (firstElement) { //throwing away root
firstElement = false;
continue;
}
if (xmlReader.NodeType == XmlNodeType.Element) {
key = xmlReader.Name.Substring(1); //cut of "o"
} else if (xmlReader.NodeType == XmlNodeType.Text) {
kvpList.Add(new KeyValuePair<string,string>(key, xmlReader.Value));
}
}
}
Edit:
The main trick is this line:
xmlString = "<Root>" + xmlString.Replace("<", "<o").Replace("<o/", "</o") + "</Root>"; //wrap to make this having single root, o is put to force the tagName started with known letter (comment edit suggested by Mr. chwarr)
Where you first replace all opening pointy brackets with itself + char, i.e.
<1>text1</1> -> <o1>text1<o/1> //first replacement, fix the number issue
and then reverse the sequence of all the opening point brackets + char + forward slash to opening point brackets + forward slash + char
<o1>text1<o/1> -> <o1>text1</o1> //second replacement, fix the ending tag issue
Using simple WinForm with RichTextBox to print out the result,
for (int i = 0; i < kvpList.Count; ++i) {
richTextBox1.AppendText(kvpList[i].Key + " = " + kvpList[i].Value + "\n");
}
Here is the result I get:
This is far from bulletproof, but you could use a combination of split and Regex matching:
string exampleString = "<1>text1</1><27>text27</27><3>text3</3>";
string[] results = exampleString.Split(new string[] { "><" }, StringSplitOptions.None);
Regex r = new Regex(#"^<?(\d+)>([^<]+)<");
foreach (string result in results)
{
Match m = r.Match(result);
if (m.Success)
{
string index = m.Groups[1].Value;
string value = m.Groups[2].Value;
}
}
The most non-bulletproof example I can think of is if your text contains a "<", that would pretty much break this.
My code searches through a list and then if it finds a match, it displays the object in my listbox. My problem is that if there is more than 1 object in the list (if im searching for Alex and there is two objects with the name Alex), it returns it all on the same line instead of separating them to separate lines.
I coulda swore match += request + "\n"; was how to do it correctly, but it's not working.
Edit: One thing I dont understand is that if i just have match += request; it will allow me to use the horizontal scroll bar on my listbox to see everything written. And if i use match += request + "\n"; or match += request + Environment.NewLine; it doesn't let me use the scroll box and just cuts off.
public string SearchRequest(string keyword)
{
bool found = false;
string noMatch = "No requests with the name " + "'" + keyword + "'" + " were found";
string match = "";
foreach (ServiceRequest request in Requests)
{
if (request.searchKeywords(keyword))
{
match += request + "\n";
found = true;
}
}
if (found)
return match;
else
return noMatch;
}
/
public bool searchKeywords(string keyword)
{
if (keyword == name)
return true;
else
return false;
}
/
private void btnSearch_Click(object sender, EventArgs e)
{
lstSearch.Items.Clear();
lstSearch.Items.Add(myRequest.SearchRequest(txtSearch.Text));
}
Try
match += request + Environment.NewLine;
If you put all the results in a single string then it will still be a single item in the list.
Return an array of strings from the method instead of a single string:
public string[] SearchRequest(string keyword) {
List<string> match = new List<string>();
foreach (ServiceRequest request in Requests) {
if (request.searchKeywords(keyword)) {
match.Add(request.ToString());
}
}
if (match.Count > 0) {
return match.ToArray();
} else {
return new string[] { "No requests with the name " + "'" + keyword + "'" + " were found" };
}
}
Then use AddRange to add the strings as separate items in the list:
lstSearch.Items.AddRange(myRequest.SearchRequest(txtSearch.Text));
In Windows OS, the new line is two characters, the Carriage Return \r followed by Line Feed: \n. You can use Environment.NewLine as a shortcut (preferred) or append "\r\n" yourself. See further wikipedia entry on newline
Use one of these:
match += request + "\r\n";
Use an string literal:
match += request + #"
";
OR only at runtime will this resolve:
match += request + System.Environment.NewLine;
On Unix "\n"
You can't add a string with newlines to a listbox and expect it to show up as multiple items. Either split the string on newline and add each line separately to the listbox, or return a list of strings from your search function to begin with, avoiding the need for a split afterwards.
I have a filename of document erwin_01problem.doc, What i want here is the if a filename does not contain a space between 01problem (erwin_01problem.doc). I find the index of problem and replace it with " ". The output will be erwin_01 problem.doc
Here is the code that i try but still I wasn't able to put a space between 01 and problem.
if (!string.IsNullOrEmpty(job.ProblemPath))
{
job.HasProblemFile = true;
var problemDocFname = Path.GetFileName(job.ProblemPath);
if (!Regex.IsMatch(problemDocFname, #"\sproblem\.doc$"))
{
ProgM.JobStatus = "Checking space between filename and problem...";
Thread.Sleep(1000);
problemDocFname = problemDocFname.Insert(problemDocFname.IndexOf("problem.doc", StringComparison.Ordinal), " ");
//problemDocFname = problemDocFname.Replace("problem", " problem");
}
problemDocFname = Path.Combine(job.FilePath, problemDocFname);
var docProblemCount = 0;
ProgM.JobStatus = "Correcting the Format of Problem Doc...";
Thread.Sleep(1000);
MicrosoftWord.CorrectProblemDocFormatting(problemDocFname, ref docProblemCount);
}
jobs.Add(job);
I belive you don't really need regular expressions. You can just do something like:
string key = "problem.doc";
if (problemDocFname.EndsWith(key) && problemDocFname.Length > key.Length)
{
problemDocFname.Replace(key, " problem.doc");
}
Struggling with a C# Component. What I am trying to do is take a column that is ntext in my input source which is delimited with pipes, and then write the array to a text file. When I run my component my output looks like this:
DealerID,StockNumber,Option
161552,P1427,Microsoft.SqlServer.Dts.Pipeline.BlobColumn
Ive been working with the GetBlobData method and im struggling with it. Any help with be greatly appreciated! Here is the full script:
public override void Input0_ProcessInputRow(Input0Buffer Row)
{
string vehicleoptionsdelimited = Row.Options.ToString();
//string OptionBlob = Row.Options.GetBlobData(int ;
//string vehicleoptionsdelimited = System.Text.Encoding.GetEncoding(Row.Options.ColumnInfo.CodePage).GetChars(OptionBlob);
string[] option = vehicleoptionsdelimited.Split('|');
string path = #"C:\Users\User\Desktop\Local_DS_CSVs\";
string[] headerline =
{
"DealerID" + "," + "StockNumber" + "," + "Option"
};
System.IO.File.WriteAllLines(path + "OptionInput.txt", headerline);
using (System.IO.StreamWriter file = new System.IO.StreamWriter(path + "OptionInput.txt", true))
{
foreach (string s in option)
{
file.WriteLine(Row.DealerID.ToString() + "," + Row.StockNumber.ToString() + "," + s);
}
}
Try using
BlobToString(Row.Options)
using this function:
private string BlobToString(BlobColumn blob)
{
string result = "";
try
{
if (blob != null)
{
result = System.Text.Encoding.Unicode.GetString(blob.GetBlobData(0, Convert.ToInt32(blob.Length)));
}
}
catch (Exception ex)
{
result = ex.Message;
}
return result;
}
Adapted from:
http://mscrmtech.com/201001257/converting-microsoftsqlserverdtspipelineblobcolumn-to-string-in-ssis-using-c
Another very easy solution to this problem, because it is a total PITA, is to route the error output to a derived column component and cast your blob data to a to a STR or WSTR as a new column.
Route the output of that to your script component and the data will come in as an additional column on the pipeline ready for you to parse.
This will probably only work if your data is less than 8000 characters long.
Currently I am building an agenda with extra options.
for testing purposes I store the data in a simple .txt file
(after that it will be connected to the agenda of a virtual assistant.)
To change or delete text from this .txt file I have a problem.
Although the part of the content that needs to be replaced and the search string are exactly the same it doesn't replace the text in content.
code:
Change method
public override void Change(List<object> oldData, List<object> newData)
{
int index = -1;
for (int i = 0; i < agenda.Count; i++)
{
if(agenda[i].GetType() == "Task")
{
Task t = (Task)agenda[i];
if(t.remarks == oldData[0].ToString() && t.datetime == (DateTime)oldData[1] && t.reminders == oldData[2])
{
index = i;
break;
}
}
}
string search = "Task\r\nTo do: " + oldData[0].ToString() + "\r\nDateTime: " + (DateTime)oldData[1] + "\r\n";
reminders = (Dictionary<DateTime, bool>) oldData[2];
if(reminders.Count != 0)
{
search += "Reminders\r\n";
foreach (KeyValuePair<DateTime, bool> rem in reminders)
{
if (rem.Value)
search += "speak " + rem.Key + "\r\n";
else
search += rem.Key + "\r\n";
}
}
// get new data
string newRemarks = (string)newData[0];
DateTime newDateTime = (DateTime)newData[1];
Dictionary<DateTime, bool> newReminders = (Dictionary<DateTime, bool>)newData[2];
string replace = "Task\r\nTo do: " + newRemarks + "\r\nDateTime: " + newDateTime + "\r\n";
if(newReminders.Count != 0)
{
replace += "Reminders\r\n";
foreach (KeyValuePair<DateTime, bool> rem in newReminders)
{
if (rem.Value)
replace += "speak " + rem.Key + "\r\n";
else
replace += rem.Key + "\r\n";
}
}
Replace(search, replace);
if (index != -1)
{
remarks = newRemarks;
datetime = newDateTime;
reminders = newReminders;
agenda[index] = this;
}
}
replace method
private void Replace(string search, string replace)
{
StreamReader reader = new StreamReader(path);
string content = reader.ReadToEnd();
reader.Close();
content = Regex.Replace(content, search, replace);
content.Trim();
StreamWriter writer = new StreamWriter(path);
writer.Write(content);
writer.Close();
}
When running in debug I get the correct info:
content "-- agenda --\r\n\r\nTask\r\nTo do: test\r\nDateTime: 16-4-2012 15:00:00\r\nReminders:\r\nspeak 16-4-2012 13:00:00\r\n16-4-2012 13:30:00\r\n\r\nTask\r\nTo do: testing\r\nDateTime: 16-4-2012 9:00:00\r\nReminders:\r\nspeak 16-4-2012 8:00:00\r\n\r\nTask\r\nTo do: aaargh\r\nDateTime: 18-4-2012 12:00:00\r\nReminders:\r\n18-4-2012 11:00:00\r\n" string
search "Task\r\nTo do: aaargh\r\nDateTime: 18-4-2012 12:00:00\r\nReminders\r\n18-4-2012 11:00:00\r\n" string
replace "Task\r\nTo do: aaargh\r\nDateTime: 18-4-2012 13:00:00\r\nReminders\r\n18-4-2012 11:00:00\r\n" string
But it doesn't change the text. How do I make sure that the Regex.Replace finds the right piece of content?
PS. I did check several topics on this, but none of the solutions mentioned there work for me.
You missed a : right after Reminders. Just check it again :)
You could try using a StringBuilder to build up you want to write out to the file.
Just knocked up a quick example in a console app but this appears to work for me and I think it might be what you are looking for.
StringBuilder sb = new StringBuilder();
sb.Append("Tasks\r\n");
sb.Append("\r\n");
sb.Append("\tTask 1 details");
Console.WriteLine(sb.ToString());
StreamWriter writer = new StreamWriter("Tasks.txt");
writer.Write(sb.ToString());
writer.Close();