wpf richtextbox selection with regex - regex

i want to color the matched text of a file.
first,i load the file text into FileItem.Content ,then use regex to get the matches,and next put the Content into a richtextbox and use the matches to set the caret position and color the text .
and the code to fill richtextbox
RtbCodes.Document.Blocks.Clear();
RtbCodes.Document.Blocks.Add(new Paragraph(new Run(item.Content)));
foreach (Match m in item.Matches)
{
TextPointer start1 = RtbCodes.Document.ContentStart.GetPositionAtOffset(m.Index, LogicalDirection.Forward);
TextPointer end = RtbCodes.Document.ContentStart.GetPositionAtOffset(m.Index + m.Length, LogicalDirection.Backward);
if (start1 != null && end != null)
{
RtbCodes.Selection.Select(start1, end);
RtbCodes.Selection.ApplyPropertyValue(Run.BackgroundProperty, "red");
}
}
my problem is the caret selection is not correct at all. see the picture bellow.
my regex expression is [\$#]{[.a-zA-Z\d]+} ,so it will get #{blacklist.model1} , but it not.
so ,what's wrong with richtextbox ?

You are counting in the invisible "ElementStart" symbols at the beginning of the document, that's why the offset of the selection is incorrect.
To get the correct position, you can count from the beginning of the Run element.
var newRun = new Run(item.Content);
RtbCodes.Document.Blocks.Add(new Paragraph(newRun));
TextPointer start1 = newRun.ContentStart.GetPositionAtOffset(m.Index, LogicalDirection.Forward);
TextPointer end = newRun.ContentStart.GetPositionAtOffset(m.Index + m.Length, LogicalDirection.Backward);

Related

Is it possible to match a nested pair with regex?

Im attempting to parse some BBCode with regex, but the nested structures are giving me a headache
What I'm trying to parse is the following:
[COLOR="Red"]Red [COLOR="Green"]Green[/COLOR][/COLOR]
I've come up with the following pattern, which I need to deal with the quotation marks around the color attribute, but it only matches the first leading COLOR and the first closing COLOR. Its not matching in a proper nested arrangement
\[COLOR=(\"?)(.*?)(\"?)]([\s\S]*?)\[\/COLOR\]\
Its being done in dart, as follows, but really I believe the problem might be with my regex pattern rather then the dart implementation
text = text.replaceAllMapped(RegExp(r'\[COLOR=(\"?)(.*?)(\"?)]([\s\S]*?)\[\/COLOR\]', caseSensitive: false, multiLine: true), (match) {
return '<font style="color: ${match.group(2)}">${match.group(4)}</font>';
});
Matching braces (of any kind) are not regular. It's known to be a problem which is context free (can be solved by a stack machine or specified by a context free grammar), but not regular (can be solved by a finite state machine or specified by a regular expression).
While the commonly implemented "regular expressions" can do some non-regular things (due to backreferences), this is not one of those things.
In general, I'd recommend using a RegExp to tokenize the input, then build the stack based machine yourself on top.
Here, because it's simple enough, I'd just match the start and end markers and replace them individually, and not try to match the text between.
var re = RegExp(r'\[COLOR="(\w+)"\]|\[/COLOR\]');
text = text.replaceAllMapped(re, (m) {
var color = m[1]; // The color of a start tag, null if not start tag.
return color == null ? "</span>" : ​"<span style='color:$color'>";
});
If you want to check that the tags are balanced, we're back to having a stack (in this case so simple it's just a counter):
var re = RegExp(r'\[COLOR="(\w+)"\]|\[/COLOR\]');
var nesting = 0;
text = text.replaceAllMapped(re, (m) {
var color = m[1];
if (color == null) {
if (nesting == 0) {
throw ArgumentError.value(text, "text", "Bad nesting");
}
nesting--; // Decrement on close tag.
return "</span>";
}
nesting++; // Increment on open-tag.
return ​"<span style='color:$color'>";
});
if (nesting != 0) {
throw ArgumentError.value(text, "text", "Bad nesting");
}

How can I replace a character in an OnChanging event using Regex and keeping the caret at the end of the EditText in ExtendScript?

I need to type in a TextBox and see instantly the result in a StaticText. In order to avoid " " (space character), I'm replacing it using Regex.
It is working but the cursor moves to the left every time when a space key is pressed. It is being replaced by "_" but because the cursor moves to the first position in my EditText box, it makes impossible to proceed typing fluently.
editText.onChanging = function(){
if (this.text.match(/\s*$/i)) {
this.text = this.text.replace(/ /g, "_");
}
staticText.text = this.text;
}
How can I type in that edittext, replacing every space character and keeping the cursor at the end of the line?
I have found the solution.
To replace a character using Regex and keep the caret at the end of the line, you should save the result from the replacement in a variable, clear the text box and use a textselection to bring it back to your edittext box.
editText.onChanging = function(){
if (this.text.match(/\s*$/i)) {
var text = this.text.replace(/ /g, "_");
this.text = "";
this.textselection = text;
}
staticText.text = this.text;
}

Notepad++ or UltraEdit: regex remove special duplicates

I need to remove duplicates if
key = anything
but NOT
key=anything
the key can be anything too
e.g.
edit_home=home must be in place
while
edit_home = home or even other string must be removed IF edit_home is a duplicate
for all the lines of the document
thank you
p.s. clearer example:
one=you are
two=we are
three_why=8908908
one = good
two = fine
three_4 = best
three_why = win
from that list i only need to keep:
one=you are
two=we are
three_why=8908908
three_4 = best // because three_4 doesn't have a duplicate
I found a method to do it, but I would need a better search list support by regex or a plugin or a direct regex (which I don't know).
That is: I have two files to compare.
One has the full keys, the other has incomplete.
I merge in a new file all the keys from the first file with those ones of the second, in groups (because the keys are in groups e.g. many keys titled one, many titled two and so on...). Then I regex replace all the keys in the new file by
find (.*)(\s\=\s) replace with \1\=
So they all become key=anything
Then I replace everything after = with empty to isolate the keys.
Then remove the duplicates.
At this point I have trouble to do something like
^.*(^keyone\b|^keytwo\b|^keythree\b).*$
to find all those keys in the document I need. So from that I can select all and replace with the correct keys.
Why? Because in this example the keys are 3 only BUT indeed the keys are many and the find field breaks at a certain point.
How to do it right?
Update: I found Toolbucket plugin which allows to search for many strings, but another issue is that in addition to duplicate, I also have to remove the original.
That is, if I find 2 times the same key "one" I have to remove all the lines containing one.
Ctrl + F
Find tab
Find what: ^.*\S=\S.*$
Find All in Current Document
Copy result from result window to a new window (the list of Line 1: Line 2: Line 3: ...)
Ctrl + F
Replace tab
(the following will remove the leading "Line number:" from every line)
Find what: ^.*?\d:\s
Replace with: Empty
ok, after all that i wrote, one solution could be (therefore, once i have the merged keys)
(?m)^(.*)$(?=\r?\n^(?!\1).*(?s).*?\1)
with this i can mark/highlight all the duplicated keys :-) so then i can manage those only, removing them from the first list and adding what remains to the second file...
If someone has a solution with a direct regex will be really appreciated
Here is a commented UltraEdit script for this task.
// Note: This script does not work for large files as it loads the
// entire file content into very limited scripting memory for fast
// processing even with multiple GB of RAM installed.
if (UltraEdit.document.length > 0) // Is any file opened?
{
// Define environment for this script and select entire file content.
UltraEdit.insertMode();
UltraEdit.columnModeOff();
UltraEdit.activeDocument.selectAll();
// Determine line termination used currently in active file.
var sLineTerm = "\r\n";
if (typeof(UltraEdit.activeDocument.lineTerminator) == "number")
{
// The two lines below require UE v16.00 or UES v10.00 or later.
if (UltraEdit.activeDocument.lineTerminator == 1) sLineTerm = "\n";
else if (UltraEdit.activeDocument.lineTerminator == 2) sLineTerm = "\r";
}
else // This version of UE/UES does not offer line terminator property.
{
if (UltraEdit.activeDocument.selection.indexOf(sLineTerm) < 0)
{
sLineTerm = "\n"; // Not DOS, perhaps UNIX.
if (UltraEdit.activeDocument.selection.indexOf(sLineTerm) < 0)
{
sLineTerm = "\r"; // Also not UNIX, perhaps MAC.
if (UltraEdit.activeDocument.selection.indexOf(sLineTerm) < 0)
{
sLineTerm = "\r\n"; // No line terminator, use DOS.
}
}
}
}
// Get all lines of active file into an array of strings
// with each string being one line from active file.
var asLines = UltraEdit.activeDocument.selection.split(sLineTerm);
var nTotalLines = asLines.length;
// Process each line in the array.
for(var nCurrentLine = 0; nCurrentLine < asLines.length; nCurrentLine++)
{
// Skip all lines not containing or starting with an equal sign.
if (asLines[nCurrentLine].indexOf('=') < 1) continue;
// Get string left to equal sign with tabs/spaces trimmed.
var sKey = asLines[nCurrentLine].replace(/^[\t ]*([^\t =]+).*$/,"$1");
// Skip lines beginning with just tabs/spaces left to equal sign.
if (sKey.length == asLines[nCurrentLine].length) continue;
var_dump(sKey);
// Build the regular expression for the search in all other lines.
var rRegSearch = new RegExp("^[\\t ]*"+sKey+"[\\t ]*=","g");
// Ceck all remaining lines for a line also starting with
// this key string case-sensitive with left to an equal sign.
var nLineCompare = nCurrentLine + 1;
while(nLineCompare < asLines.length)
{
// Does this line also has this key left to equal
// sign with or without surrounding spaces/tabs?
if (asLines[nLineCompare].search(rRegSearch) < 0)
{
nLineCompare++; // No, continue on next line.
}
else // Yes, remove this line from array.
{
asLines.splice(nLineCompare,1);
}
}
}
// Was any line removed from the array?
if (nTotalLines == asLines.length)
{
UltraEdit.activeDocument.top(); // Cancel the selection.
UltraEdit.messageBox("Nothing found to remove!");
}
else
{
// If version of UE/UES supports direct write to clipboard, use
// user clipboard 9 to paste the lines into file with overwritting
// everything as this is much faster than using write command in
// older versions of UE/UES.
if (typeof(UltraEdit.clipboardContent) == "string")
{
var nActiveClipboard = UltraEdit.clipboardIdx;
UltraEdit.selectClipboard(9);
UltraEdit.clipboardContent = asLines.join(sLineTerm);
UltraEdit.activeDocument.paste();
UltraEdit.clearClipboard();
UltraEdit.selectClipboard(nActiveClipboard);
}
else UltraEdit.activeDocument.write(asLines.join(sLineTerm));
var nRemoved = nTotalLines - asLines.length;
UltraEdit.activeDocument.top();
UltraEdit.messageBox("Removed " + nRemoved + " line" + ((nRemoved != 1) ? "s" : "") + " on updated file.");
}
}
Copy this code and paste it into a new ASCII file using DOS line terminators in UltraEdit.
Next use command File - Save As to save the script file for example with name RemoveDuplicateKeys.js into %AppData%\IDMComp\UltraEdit\MyScripts or wherever you want to have saved your UltraEdit scripts.
Open Scripting - Scripts and add the just saved UltraEdit script to the list of scripts. You can enter a description for this script, too.
Open the file with the list, or make this file active if it is already opened in UltraEdit.
Run the script by clicking on it in menu Scripting, or by opening Views - Views/Lists - Script List and double clicking on the script.

JScript regexp: start of line doesn't work?

I want to cut path from config file:
var out = '#Path to the database root';
out += '\ndatadir="C:/Program Files/MySQL/MySQL Server 5.0/Data/"';
out += '\nblah-blah-blah-blah-blah';
var re = new RegExp('^datadir="(.*)"', 'g');
var result = out.match(re);
if (result == null){
WScript.Echo("datadir not found");
}
WScript.Echo("datadir=" + RegExp.lastParen);
but my code doesn't found the required string. On the other hand, if i remove the 'caret' symbol (^) it works. It's not a solution because I want to make sure I grab data from line which really starts with that word.
Update:
In fact '\n' is really the new line for me despite single quote. For example
WScript.Echo("out=" + out);
produces
out=#Path to the database root
datadir="C:/Program Files/MySQL/MySQL Server 5.0/Data/"
blah-blah-blah-blah-blah
What am I doing wrong?
A ^ boundary normally anchors to the beginning of the entire input string rather than the beginning of each individual line.
The m flag can be used to anchor at each line instead:
var re = new RegExp('^datadir="(.*)"', 'gm');
Example: http://jsfiddle.net/PjLd4/

How to change the position where next character will be place in the Edit Control from MFC?

I have piece of code that erases the last character of a string and then set the text in the Edit Control to that new string. The problem is that, afterwards, the position of the character that will be typed next changes.
Example:
Edit control box: [ 12345| ] (The slash is where the next character
typed will be placed)
After doing the code mentioned
Edit control box: [ |12345 ] (The position now moved to the front,
before 1)
How would I move the position to the end of the string again?
My code:
CString str1 = ""; //Temporary CString
eb1->GetWindowText(str1); //Store text from Edit Control to the CString
string strCheck1 = str1.GetString(); //Place the CString into a regular string
int s1 = strCheck1.length() -1; //Get index of last character and new size
bool check1 = true; //Boolean variable for the checking
//Get if character is valid
if((strCheck1[s1] <= '0' || strCheck1[s1] >='9') && strCheck1[s1] != '.') {check1 = false;}
//If is invalid I erase last character and put it back intact into the Edit Control
if(check1 == false) {strCheck1.erase(s1,1); eb1->SetWindowTextA(strCheck1.c_str());}
Have you tried SetSel() operation of edit control?
// get the initial text length
int nLength = edit.GetWindowTextLength();
// put the selection at the end of text
edit.SetSel(nLength, nLength);
You can use CEdit::SetSel() (I'm assuming that you are using CEdit). Just let the start and end of selection both be the end of string, you should be able to move the cursor there. Details may be found at http://msdn.microsoft.com/en-us/library/w9kftda4(v=vs.80).aspx