GetPositionAtOffset() don't return good position - regex

I use a RichTextBox in WPF (4.0) and I use the GetPositionAtOffset() method to get a text range between two position in the content in RichTextBox.
1) I initialize the text pointer "position" from MyRichTextBox.Document.ContentStart :
TextPointer position = RTBEditor.Document.ContentStart;
2) I get the text from my RichTextBox like that :
var textRun = new TextRange(RTBEditor.Document.ContentStart, RTBEditor.Document.ContentEnd).Text;
3) With Regex I find a string that I want in textRun and get the begin's index and the end's index (I search a text between "/*" and "*/"):
Regex regex = new Regex(#"/\*([^\*/])*\*/");
var match = regex.Match(textRun);
TextPointer start = position.GetPositionAtOffset(matchBegin.Index, LogicalDirection.Forward);
TextPointer end = position.GetPositionAtOffset(matchBegin.Index + matchBegin.Length, LogicalDirection.Backward);
But, when I use these pointers in a textrange and colorize the text inside, it's not the good text matched in my regex (with goods indexes) which is colorized in my RichTextBox.
Why the GetPositionAtOffset() method don't give the position at the index specified ? It's this method the problem or it's somewhere else ?
Thank's for reply, I am stopped in my development.

According to this, https://msdn.microsoft.com/en-us/library/ms598662%28v=vs.110%29.aspx
GetPositionAtOffset returns a TextPointer to the position indicated by the specified offset, in symbols, from the beginning of the current TextPointer.
Any of the following is considered to be a symbol:
An opening or closing tag for the TextElement element.
A UIElement element contained in an InlineUIContainer or BlockUIContainer. Note that such a UIElement is always counted as exactly one symbol; any additional content or elements contained by the UIElement are not counted as symbols.
A 16-bit Unicode character inside of a text Run element.

Sorry to bother you, the problem was somewhere else.
I initialized the text of my RichTextBox with AppendText() method and not with a paragraph that I added in the blocks. So now it works fine !

Related

How do you select specific range in a string using RegEx

So I have a string. Let's say for the argument it is this one:
1234567891113SomeTextExample
I want to have two regular expresions:
Select from beginning to, say, 6th position;
Select from 8th position to 12th position.
I know how to select everything AFTER specific position, e.g.:
(?<=.{6})(.*)$
would select everything after 5 characters.
I am using Sublime Text editor and need to cleanup some logs and these two expressions would save a whole lot of time.
use ^ to get your regex to start at the beginning.
Beginning to 6th position : ^(.{6})
var str = 'xdcfvgbhdsds';
var regex = /^(.{6})/;
console.log(regex.exec(str)[1]);
8th to 12th position : ^.{7}(.{5})
var str = 'xdcfvgbhddsfsffsds';
var regex = /^.{7}(.{5})/;
console.log(regex.exec(str)[1]);
Beginning to 6th position (Demo):
^(.{6}).*$
Characters 8 to 12, inclusive on both ends (Demo):
^.{7}(.{5}).*$
I am assuming here that you want to capture these specific ranges for some sort of use.
Finally I found it out.
First one - Select from beginning to, say, 6th position:
^(.{6})
Thanks Zenoo for this.
And select from 8th position to 12th position:
^(.{8})|(?<=.{12})(.*)$
Well, at least this one works in Sublime Text. I am sure there are lots and lots of editors/applications which are fine with Zenoo's approach (^.{7}(.{5})).

VBA code to check is value from array in present in a cell?

I need to loop though a cell range that contains one or several locale ISO codes in a CSV fashion e.g esES, frFR, itIT, etc.
If ANY of these values are contained within a cell, I select it and paste it to another workbook. The latter part I got covered, but I can't figure how to make the former part work. This is the code I'm working with at the moment:
OTHERS_V = "*arAR*|*bgBG*|*csCZ*|*daDK*"
For Each cell In Intersect(Sheets("Requests").Range("G:G"), Sheets("Requests").UsedRange)
If cell.Value Like OTHERS_V Then [...]
I'm pretty new to VBA and I don't know much about Regex in this language but from my experience this should read something like:
(anything + "arAR" + anything) OR (anything + "bgBG" + anything) OR [...]
etc.
It doesn't seem to work though. How would you go about accomplishing what I'm after in this context?
As per my comments, put OTHERS_V list in an array and loop testing each one:
Sub fooo()
Dim OTHERS_V()
Dim cell As Range
Dim i As Long
OTHERS_V = Array("*arAR*", "*bgBG*", "*csCZ*", "*daDK*")
For Each cell In Intersect(Sheets("Requests").Range("G:G"), Sheets("Requests").UsedRange)
For i = LBound(OTHERS_V) To UBound(OTHERS_V)
If cell.Value Like OTHERS_V(i) Then
'do your stuff
Exit For
End If
Next i
Next cell
End Sub

Regex - Match all subsections

I have the following strings which indicate a hierarchy:
JHW/1/24/3/562 // child row
JHW/1/24/3 // parent of the above
JHW/1/24 // parent of the above
JHW/1 // parent of the above
JHW // parent of the above
What I'd like to do is to be able to pull out all of the "parent" rows with one regex.
The closest I've got conceptually (which isn't anywhere near) is #^([^/]*/)+# which just matches the second-last section [eg. 3].
I've never really tried to do something like this before, where I'm trying to get overlapping results - it is possible? It's not an issue if it brings back the child row as one of the matches.
You can't obtain several results from the same position (since the regex engine go to the next character after each try of the pattern), you can explode the string with / and build each path you need with the array items.
An other possible way consists to reverse the string:
preg_match_all('~(?=(?:\A|/)(.+))~', strrev($path), $m);
$result = array_map('strrev', $m[1]);

RichTextBox search'n'replace results are staggered

I am currently trying to generate colored results after a search containing keywords. My code displays a richtextbox containing a text that was succesfully hit by the search engine.
Now I want to highlight the keywords in the text, by making them bold and colored in red. I have my list of words in a nice string table, which I browse this way (rtb is my RichTextBox, plainText is the only Run from rtb, containing the entire text of it) :
rtb.SelectAll();
string allText = rtb.Selection.Text;
string expression = "";
foreach (string word in words)
{
expression = Regex.Escape(word);
Regex regExp = new Regex(expression);
foreach (Match match in regExp.Matches(allText))
{
TextPointer start = plainText.ContentStart.GetPositionAtOffset(match.Index, LogicalDirection.Forward);
TextPointer end = plainText.ContentStart.GetPositionAtOffset(match.Index + match.Length, LogicalDirection.Forward);
rtb.Selection.Select(start, end);
rtb.Selection.ApplyPropertyValue(Run.FontWeightProperty, FontWeights.Bold);
rtb.Selection.ApplyPropertyValue(Run.ForegroundProperty, "red");
}
}
Now I thought this would do the trick. But somehow, only the first word gets highlighted correctly. Then, the second occurence of the highlights starts two early, with the correct amount of letters getting highlighted, but a few characters before the actual word. Then for the third occurence it's further more characters earlier, etc.
Have you got any idea what is causing this behavior?
EDIT (01/07/2013): Still not figuring out why these results are staggered... So far I noticed that if I created a variable set to zero right before the second foreach statement, added it up to each textpointer's positions and incremented it by 4 (no idea why) at the end of each loop, the results are colored adequately. Nevertheless, if I search for two keywords or more (doesn't matter if they're the same size), each occurence of the first keyword get colored correctly, but only the first occurences of the other keywords are well-colored. (the others are staggered again) Here's the edited code:
rtb.SelectAll();
string allText = rtb.Selection.Text;
string expression = "";
foreach (string word in words)
{
expression = Regex.Escape(word);
Regex regExp = new Regex(expression);
int i = 0;
foreach (Match match in regExp.Matches(allText))
{
TextPointer start = plainText.ContentStart.GetPositionAtOffset(match.Index + i, LogicalDirection.Forward);
TextPointer end = plainText.ContentStart.GetPositionAtOffset(match.Index + match.Length + i, LogicalDirection.Forward);
rtb.Selection.Select(start, end);
rtb.Selection.ApplyPropertyValue(Run.FontWeightProperty, FontWeights.Bold);
rtb.Selection.ApplyPropertyValue(Run.ForegroundProperty, "red");
i += 4; // number found out from trials
}
}
Alright! So I learned by reading this question that everytime I modify the style, it adds 4 characters to the text, which is what was messing up my setting.
In order to fix this, since I possibly have multiple keywords and that they do not appear one after the other in the text in the order that they were typed in the search box, I had to first browse my text to locate each occurence for each keyword without modifying the text. For each occurence, I store in a custom list the start position, end position and desired color of the occurence.
When this selection is done, I order my occurence list by the start attribute of each member in it. I can now be assured that each occurence I browse in my foreach loop is the next one in the text, with no regard to its content or length. And I know in which color I want to make it appear, so I can distinguish different keywords.
Then, finally, I can browse each member of my ordered list and modify the style of my text, knowing that the next word will appear later in the text, so I must add 4 characters to my index at the end of each loop.

regular expressions and vba

Does anyone know how to extract matches as strings from a RegExp.Execute() function?
Let me show you what I've gotten to so far:
Regex.Pattern = "^[^*]*[*]+"
Set myMatches = Regex.Execute(temp)
I want the object "myMatches" which is holding the matches, to be converted to a string. I know that there is only going to be one match per execution.
Does anyone know how to extract the matches from the object as Strings to be displayed lets say via a MsgBox?
Try this:
Dim sResult As String
'// Your expression code here...
sResult = myMatches.Item(0)
'// or
sResult = myMatches(0)
Msgbox("The matching text was: " & sResult)
The Execute method returns a match collection and you can use the item property to retrieve the text using an index.
As you stated you only ever have one match then the index is zero. If you have more than one match you can return the index of the match you require or loop over the entire collection.
This page has a lot of information on regex and seems to have what you want.
http://www.regular-expressions.info/vbscript.html