Range.Find.Execute - Forward only misbehave - c#

I'm using the .Net libraries for Microsoft Word 2010 interoping
Word.Document doc = wb.Documents[1];
Word.Range range = doc.Range();
range.Find.Forward = true;
range.Find.Execute("HELLO");
MessageBox.Show("Start " + range.Start.ToString());
MessageBox.Show("End " + range.End.ToString());
//make sure it won't even look back
range.Start = range.End;
range.Find.Execute("HELLO");
MessageBox.Show("Start " + range.Start.ToString());
MessageBox.Show("End " + range.End.ToString());
if the document has more than one "HELLO" in it, the range that is returned just ignores it, it keeps finding the same string, I keep getting the same range.Start and range.End values over and over again. what am i missing here ?

I isolated the problem and it seem to happen only when there's special characters in the word document, particularity if text is contained inside a custom table. on normal plain documents it works fine.
I ended up sampling the range.Start value after each search, if it was the same as the prior one, I increase it's start range by + 1 and then re-search.
This is done again and again and although it adds a few more searches it's quite stable.
while (range.text.Contains("HELLO"))
{
range.Find.Execute("HELLO");
while ((range.Start < intLastFoundRangeStartValue) && (range.Find.Found))
{
range.Start += intAddToRangeStartValue;
intAddToRangeStartValue++;
range.Find.Execute("HELLO");
}
}
...
In addition as a by-product it relives me from the need to add a counter to the loop.

Related

Can't get Messagebox to display List

I'm trying to have a MessageBox appear that shows the changelog inside my C# program
This is the text file.
Current Version 0.2.3.4
Added Hash decoder
Attempted to change code into OOP design
Cleaned up random code with ReSharper
Version 0.1.3.4 - 8/29/2016
No change logs before this point
The goal is to get the text between Current Version 0.2.3.4 and Version 0.1.3.4 - 8/29/2016
I've had tried doing this with the code below
Regex changeLogMatch = new Regex("Current Version\\s.*?\\n(.*?\\n)+Version\\s.*?\\s\\-\\s\\d");
Match changeLogInfo = changeLogMatch.Match(changeLog);
int changeLogCount = Regex.Matches(changeLog, "Current Version\\s.*?\\n(.*?\\n)+Version\\s.*?\\s\\-\\s\\d").Count;
List<string> changeLogList = new List<string>();
for (int i = 0; i < changeLogCount; i++)
{
changeLogList.Add(changeLogInfo.Groups[1].Captures[i].ToString());
}
string changeLogString = string.Join(Environment.NewLine, changeLogList);
Console.WriteLine(changeLogString);
MessageBox.Show("New Changes" + Environment.NewLine + changeLogString
, "New Version Found: " + newVersion);
The issue I'm having is that changeLogString only displays Added Hash decoder and nothing else.
Any ideas on what I'm doing wrong?
In your case changeLogCount always be 1. So in changeLogList will be always changeLogInfo.Groups[1].Captures[0].ToString() what is refers to Added Hash decoder string.
You are checking for "Current Version\\s.*?\\n((.*?\\n)+)Version\\s.*?\\s\\-\\s\\d" regex, it is matching the whole string and matches 1 time. But the first group (.*?\\n) matches 3 times. So, if you are checking for count of matches of full regex - you will get 1, if you want to get number of captures of first group - you will get 3.
So you should fix your code in the following manner:
Regex changeLogMatch = new Regex("Current Version\\s.*?\\n(.*?\\n)+Version\\s.*?\\s\\-\\s\\d");
Match changeLogInfo = changeLogMatch.Match(changeLog);
string changeLogString = string.Join(Environment.NewLine, changeLogInfo.Groups[1].Captures.OfType<Capture>());
Console.WriteLine(changeLogString);
Note, that you have no need to iterate through captures - the required string will be stored in changeLogString.

Comparing excel sheet to text file

I have the following data from an excel sheet:
06:07:00 6:07
Data1
Data2
Data3
Data4
06:15:00 06:15
Data5
Data6
Data7
Data8
I want to compare this to the following data from text file:
XXXXXXXXXX 06:08:32 13.0 Data1
XXXXXXXXXX 06:08:45 6.0 Data2
xxxxxxxxxx 06:08:51 5.0 Data3
xxxxxxxxxx 06:08:56 13.0 Data4
xxxxxxxxxx 06:13:44 9.0 Data5
xxxxxxxxxx 06:13:53 11.0 Data6
xxxxxxxxxx 06:14:04 6.0 Data7
xxxxxxxxxx 06:14:10 13.0 Data8
As I want to use the time to compare the two files (excel with text), Time is different for each group. Group1(data1 to Data4), group2 (Data5-data8).
Does anyone have any idea how to go about this situation.
EDIT1:
Here is what I tried to do:
private void doTest(string time)
{
TimeSpan ts = TimeSpan.Parse(time);
int hours = ts.Hours;
int min = ts.Minutes;
int sec = ts.Seconds;
int minstart, minend;
string str;
minstart = min - 5;
minend = min + 5;
while (min != minend)
{
sec = sec + 1;
if (sec < 60)
{
if (hours < 10)
str = hours.ToString().PadLeft(2, '0');
else str = hours.ToString();
if (minstart < 10)
str = str + minstart.ToString().PadLeft(2, '0');
else str = str + minstart.ToString();
if (sec < 10)
str = str + sec.ToString().PadLeft(2, '0');
else str = str + sec.ToString();
chkwithtext(str);
}
else if (sec == 60)
{
sec = 00;
min = min + 1;
str = hours.ToString() + min.ToString() + sec.ToString();
chkwithtext(str);
}
}
}
private void chkwithtext(string str)
{
// check with the text file here if time doesn't match go
// back increment the time with 1sec and then check here again
}
It's not precisely clear how you are 'comparing' the times, but for this answer I'll make the assumption that data from the text file is to be compared if, and only if, its timestamp is within x minutes (defaulting to x = 5) of the Excel timestamp.
My recommendation would be to use an Excel add-in called Schematiq for this - you can download this (approx. 9MB) from http://schematiq.htilabs.com/ (see screenshots below). It's free for personal, non-commercial use. (Disclaimer: I work for HTI Labs, the authors of Schematiq.)
However, I'd do the time handling in Excel. First we'll calculate the start/stop limits for the Excel timestamps. For example, for the first time (06:07:00) we want the range 6:02-6:12. We'll also break the actual, 'start' and 'end' times into hours, minutes and seconds for ease later on. The Excel data sheet looks like this:
Next we need a Schematiq 'template function' which will take the start and end times and return us a range of times. This template is shown here:
The input values to this function are effectively 'dummy' values - the function is compiled internally by Schematiq and can then be called with whatever inputs are required. The 'Result' cell contains text starting with '~#...' (and likewise several of the previous cells) - this indicates a Schematiq data-link containing a table, function or other structure. To view it, you can click the cell and look in the Schematiq Viewer which appears as a task pane within Excel like this:
In other words, Schematiq allows you to hold an entire table of data within a single cell.
Now everything is set up, we simply import the text file and get Schematiq to do the work for us. For each 'time group' within the Excel data, a suitable range of times is generated and this is matched against the text file. You are returned all matching data, plus any unmatched data from both Excel and the text file. The necessary calculations are shown here:
Your Excel worksheet is therefore tiny, and clicking on the final cell will display the final results in the Schematiq Viewer. The results, including the Excel data and the 'template calculation', are shown here:
To be clear, what you see in this screenshot is the entire contents of the workbook - there are no other calculations taking place anywhere other than in the actual cells you see.
The 'final results' themselves are shown enlarged here:
This is exactly the comparison you're after (with a deliberately introduced error - Data9 - in the text file, to demonstrate the matching). You can then carry out whatever comparisons or further analysis you need to.
All of the data-links represent the use of Schematiq functions - the syntax is very similar to Excel and therefore easy to pick up. As an example, the call in the final cell is:
=tbl.SelectColumns(D21, {"Data","Text file"}, TRUE)
This selects all columns from the Schematiq table in cell D21 apart from the 'Data' and 'Text file' columns (the final Boolean argument to this function indicates 'all but').
I'd recommend downloading Schematiq and trying this for yourself - I'd be very happy to email you a copy of the workbook I've put together, so it should just run immediately.
I'm not sure if I understand what do you mean, but I'd start with exporting excel file to csv with ; separator - it's way much easier to work this way. Then some simple container class:
public class DataTimeContainer
{
public string Data;
public string TimeValue1 = string.Empty;
public string TimeValue2 = string.Empty;
}
And use it this way:
//Processint first file
List<DataTimeContainer> Container1 = new List<DataTimeContainer>();
string[] lines = File.ReadAllLines("c:\\data1.csv");
string groupTimeValue1 = string.Empty;
string groupTimeValue2 = string.Empty;
foreach (string[] fields in lines.Select(l => l.Split(';')))
{
//iterating over every line, splited by ';' delimiter
if (!string.IsNullOrWhiteSpace(fields[0]))
{
//we're in a line having both values, like:
//06:07:00 ; 6:07
groupTimeValue1 = fields[0];
groupTimeValue2 = fields[1];
}
else
//we're in line looking like this:
// ; DataX
Container1.Add(new DataTimeContainer(){Data = fields[1], TimeValue1 = groupTimeValue1, TimeValue2 = groupTimeValue2});
}
//Processing second file
List<DataTimeContainer> Container2 = new List<DataTimeContainer>();
lines = File.ReadAllLines("c:\\data2.txt");
foreach (string[] fields in lines.Select(l => l.Split(';')))
{
Container2.Add(new DataTimeContainer() { TimeValue1 = fields[1], TimeValue2 = fields[2], Data = fields[3]});
}
DoSomeComparison();
Of course I'm using strings as data types because I do not know what kind of objects they're supposed to be. Let me know how's that working for you.
If this is a one-time comparison, I would recommend just pulling the text file into Excel (using the Text-to-Columns tools if needed) and running a comparison there with the built-in functions.
If however you need to do this frequently, something like Tarec suggested would be a good start. It seems like you're trying to compare separate event logs within a given timespan (?) - your life will be easier if you parse to objects with DateTime properties instead of comparing text strings.
Populate your Data from your 2 sources(excel and text file) into 2 lists .
Make sure that Lists are of same type .
I would recommend Convert your Excel data to Text File Format .. and then populate Each line of text file and Excel file data into string List.
And then you can compare your List by using the LINQ or Enumerable Methods .
Quickest way to compare two List<>

c# richtextbox only shows one line

been searching the internet for some time now and cant find a solution to my problem.
I'm trying to parse some lines into the richtextbox, but i only get one line instead of all of them. Heres a part of my code
foreach (var val in lineCountDict)
{
richTextBox2.Text = (val.Key + " - " + val.Value + " Drops -" +
((double)val.Value / (double)mobDeathCounter) * 100 + " % chance\n");
}
So when i run this i only get one line, any advice would be awesome
Thank you!
Of course you get one line since in each iteration you set richTextBox2.Text to the new value which replaces the old value.
Use richTextBox2.Text+="..."

Trying to format string of Datagrid output

Hi i have the following which creates two worksheets in an excel spreadsheet based on the values in a datagrid, I am able to get it working for two datagrids, however i need to do it for 14 datagrids, this is what i have got so far;
var grid1Output = RadGridView1.ToExcelML();
var grid2Output = RadGridView2.ToExcelML().Replace("Worksheet1", "Worksheet2");
var workBook = grid1Output.Replace("</Worksheet>", "</Worksheet>" +
grid2Output.Substring(grid2Output.IndexOf("<Worksheet"),
grid2Output.IndexOf("</Worksheet")- grid2Output.IndexOf("<Worksheet")) + " </Worksheet>");
The above works fine, however I need to do it for 14 gridoutputs in total. My problem is, I am having trouble replacing strings at the right place. How do i do this?
I would probably do it with Linq for XML methods rather than string manipulation, but the choice is yours.
Either way, it shouldn't be that hard to write a method that takes a grid output (I am assuming it's a string), extracts the contents, and returns them. The calling routine then assembles the 14 XML strings and wraps them in a single Worksheet tag.
Here's a stab at it. Bear in mind that I'm not familiar with the RadGridView and the output of ToExcelML, so you probably won't be able to use this code without some modification. I'm making some assumptions that may not be valid.
First, I would create a method that takes an XML string as input. I am assuming that this string is entirely wrapped in a <Worksheetn> tag.
string ExtractWorksheetContents(string excelML, int index)
{
// You might also be able to do this with a regex, depending on how the contents are structured
// Since I don't know enough about the content, I will do this with string manipulation, as
// you did, rather than loading the XML and making assumptions.
string tagName = string.Format("Worksheet{0}", index);
int worksheetStart = excelML.IndexOf("<" + tagName);
int worksheetEnd = excelML.IndexOf("</" + tagName + ">") + tagName.Length + 3);
// Should contain some checks that neither w'sheet start nor end are -1
return excelML.Substring(worksheetStart, worksheetEnd-worksheetStart);
}
Then I would assemble the results. Again, I'm making assumptions about how the XML is structured.
StringBuilder sb = new StringBuilder();
sb.Append("<Worksheet>");
RadGridView[] gridViews = new RadGridView[] { RadGridView1, RadGridView2 .... RadGridView14 };
for(int i=0;i<14; i++)
{
var rgv = gridViews[i];
sb.Append(ExtractWorksheetContents(rgv.ToExcelML(),i+1));
}
sb.Append("</Worksheet>");
var workBook = sb.ToString();
Hope this helps somewhat.

How to add text into Word Documents at a specific position?

How do I write to a specific position in a Word document, for example, line 5, character 50? I have searched for a couple of hours, but couldn't find a solution.
I am using Microsoft.Office.Interop.Word
If you are content with the more simple sentence, rather than lines:
ActiveDocument.Sentences(1).Characters(5).Select
Selection.Collapse
Selection.InsertBefore "added "
Five paragraphs and 50 spaces in VBA
Selection.Text = String(5, vbCrLf)
Selection.Collapse wdCollapseEnd
Selection.Text = String(50, " ")
However, for a particular position, I would prefer a textbox:
Set sh = doc.Shapes.AddTextbox(1, 10, 344, 575, 80)
sh.Name = "Course1"
With some properties:
sh.Fill.Visible = False
sh.Line.Visible = False
sh.TextFrame.MarginLeft = 0#
sh.TextFrame.MarginRight = 0#
sh.TextFrame.MarginTop = 0#
sh.TextFrame.MarginBottom = 0#
If you will be inserting text at the same location every time a simple way to do this is to create a .dotx template file with a bookmark at the location. Make sure the template is included in the build
Doc = Word.Documents.Add("Directory\Filename")
Doc.Bookmarks.Item("BookmarkName").Range.Text = "Text to be inserted"
Finding a position in a word document to insert a table
You may find some useful information in the above location.

Categories

Resources