TextBox Indexof and LastIndexOf - c#

Because TextBox doesn't have a find function, I've created and modified my own version of it to my needs. I've created to functions. One for Search Next and another for Search Previous
My problem is that:
If my search term is more than 1 character long and I've searched
for the term four times, IF on the 4th term I decide the click on
search previous it goes back to the previous search term and that
works fine. Now because I clicked on search previous 4 times and I
went to the 3rd search term using previous, IF I decide to go the
4th term again using Find Next, I have to double click on find next
and then it selects the 4th term.
If my search term is 1 character long and I want to search for a
character, I type the character e.g. 'o' and it goes through each
character in the textbox but once I decide to go back using search
previous, I have to double click search previous button and then it
goes back and if I decide to search next I have to double click
again then it searches next.
This might help understand the double click and single click:
http://media.giphy.com/media/3xz2BJgF2DrtcCnP1e/giphy.gif
I've been trying to get this to work for quite a while now and I've had no luck. I have no idea where I'm going with this and before I confuse myself it will be great if someone can help me with this.
My code for:
Variables
public int startPostion = 0;
boolean passedNext;
public int pos = 0;
Search Next
public bool FindAndSelectNext(string TextToFind, bool MatchCase)
{
try
{
var mode = MatchCase ? StringComparison.CurrentCulture : StringComparison.CurrentCultureIgnoreCase;
int position = TheTextBox.Text.IndexOf(TextToFind, startPostion, mode);
pos = position;
if (position == -1)
{
var TheString = TheTextBox.Text;
var foundposition2 = TheString.IndexOf(TextToFind, mode);
TheTextBox.SelectionStart = foundposition2;
TheTextBox.SelectionLength = TextToFind.Length;
startPostion = foundposition2 + TextToFind.Length;
TheTextBox.Focus();
passedNext = false;
Debug.WriteLine("1");
return true;
}
else
{
TheTextBox.SelectionStart = position;
TheTextBox.SelectionLength = TextToFind.Length;
startPostion = position + TextToFind.Length;
TheTextBox.Focus();
passedNext = true;
Debug.WriteLine("2");
return true;
}
}
catch (Exception ex)
{
MessageBox.Show(string.Format("Could not find '{0}' in the document.", TextToFind), ProductName, MessageBoxButtons.OK, MessageBoxIcon.Information);
}
return true;
}
Search Previous
public bool FindAndSelectPrevious(string TextToFind, bool MatchCase)
{
StringComparison mode = MatchCase ? StringComparison.CurrentCulture : StringComparison.CurrentCultureIgnoreCase;
if (passedNext == true)
{
int foundPosition = startPostion < 0 ? TheTextBox.Text.Length : startPostion - 1;
foundPosition = TheTextBox.Text.LastIndexOf(TextToFind, pos, mode);
passedNext = false;
if (foundPosition < 0)
{
if (startPostion < 0)
{
MessageBox.Show(string.Format("Could not find '{0}' in the document.", TextToFind), ProductName, MessageBoxButtons.OK, MessageBoxIcon.Information);
return false;
}
foundPosition = TheTextBox.Text.LastIndexOf(TextToFind, mode);
Debug.WriteLine("1p");
}
TheTextBox.SelectionStart = foundPosition;
TheTextBox.SelectionLength = TextToFind.Length;
startPostion = foundPosition;
TheTextBox.Focus();
Debug.WriteLine("2p");
passedNext = false;
}
else
{
int foundPosition = startPostion < 0 ? TheTextBox.Text.Length : startPostion;
foundPosition = TheTextBox.Text.LastIndexOf(TextToFind, foundPosition, mode);
if (foundPosition < 0)
{
if (startPostion < 0)
{
MessageBox.Show(string.Format("Could not find '{0}' in the document.", TextToFind), ProductName, MessageBoxButtons.OK, MessageBoxIcon.Information);
return false;
}
foundPosition = TheTextBox.Text.LastIndexOf(TextToFind, mode);
}
if (!(foundPosition == -1))
{
try
{
int foundPositionz = startPostion < 0 ? TheTextBox.Text.Length : startPostion - 1;
foundPositionz = TheTextBox.Text.LastIndexOf(TextToFind, foundPositionz, mode);
TheTextBox.SelectionStart = foundPositionz;
TheTextBox.SelectionLength = TextToFind.Length;
startPostion = foundPositionz;
TheTextBox.Focus();
}
catch (Exception ex)
{
var TheString = TheTextBox.Text;
var foundposition2 = TheString.LastIndexOf(TextToFind, mode);
TheTextBox.SelectionStart = foundposition2;
TheTextBox.SelectionLength = TextToFind.Length;
startPostion = foundposition2;
TheTextBox.Focus();
Debug.WriteLine("12p");
}
}
else
{
MessageBox.Show(string.Format("Could not find '{0}' in the document.", TextToFind), ProductName, MessageBoxButtons.OK, MessageBoxIcon.Information);
}
}
return true;
}

IMHO, you should just find all the matches the first time the user tries to find something, and then keep an index indicating which match is to be selected/highlighted.
For example:
private List<int> _matches;
private string _textToFind;
private bool _matchCase;
private int _matchIndex;
private void MoveToNextMatch(string textToFind, bool matchCase, bool forward)
{
if (_matches == null ||
_textToFind != textToFind ||
_matchCase != matchCase)
{
int startIndex = 0, matchIndex;
StringComparison mode = matchCase ?
StringComparison.CurrentCulture :
StringComparison.CurrentCultureIgnoreCase;
_matches = new List();
while (startIndex < TheTextBox.Text.Length &&
(matchIndex = TheTextBox.Text.IndexOf(textToFind, startIndex, mode)) >= 0)
{
_matches.Add(matchIndex);
startIndex = matchIndex + textToFind.Length;
}
_textToFind = textToFind;
_matchCase = matchCase;
_matchIndex = forward ? 0 : _matches.Count - 1;
}
else
{
_matchIndex += forward ? 1 : -1;
if (_matchIndex < 0)
{
_matchIndex = _matches.Count - 1;
}
else if (_matchIndex >= _matches.Count)
{
_matchIndex = 0;
}
}
if (_matches.Count > 0)
{
TheTextBox.SelectionStart = _matches[_matchIndex];
TheTextBox.SelectionLength = textToFind.Length;
TheTextBox.Focus();
}
else
{
MessageBox.Show(string.Format(
"Could not find '{0}' in the document.", TextToFind),
ProductName, MessageBoxButtons.OK, MessageBoxIcon.Information);
}
}
public bool FindAndSelectNext(string textToFind, bool matchCase)
{
MoveToNextMatch(textToFind, matchCase, true);
}
public bool FindAndSelectPrevious(string textToFind, bool matchCase)
{
MoveToNextMatch(textToFind, matchCase, false);
}

Related

Why looping twice on string length test

I'm working in C# (2013) Windows Forms. My instructor wanted us to ensure that the txtStateInput is upperCase when we hit the calculate button. However when I input a two character string such as "wi" and then hit calculate, it throws the message "enter valid state" and clears out the textbox. When I enter the "wi" in a second time then it works. I can't figure out why this is happening, the code would lead me to believe that it would check to ensure the string in txtStateInput is two characters and then when calculate is clicked it would uppercase the string. I can't figure out why it only works once I enter in the state "wi" a second time.
private void btnCalc_Click(object sender, EventArgs e)
{
//declare variables.
int startPop = 0;
int endPop = 0;
string Message = "Error";
decimal Percent = 0.0m;
string State = "";
string City = String.Empty;
int dTimes = 0;
try
{
City = txtCityInput.Text;
//System Globalization was initialized so this method works.
TextInfo myTI = new CultureInfo("en-US", false).TextInfo;
txtCityInput.Text = myTI.ToTitleCase(City);
if(txtStateInput.Text.Length != 2)
{
MessageBox.Show("Enter valid State");
txtStateInput.Focus();
txtStateInput.SelectAll();
}
else
{
State = txtStateInput.Text.ToUpper();
txtStateInput.Text = State;
if ((int.TryParse(txtStartPopInput.Text, out startPop)) && int.TryParse(txtEndPopInput.Text, out endPop))
{
if ((startPop > 0) && (endPop > 0))
{
//if population has decreased.
if ((startPop > endPop))
{
Percent = ((decimal.Parse(endPop.ToString()) - decimal.Parse(startPop.ToString())) / decimal.Parse(startPop.ToString()));
Message = "Pop. Decrease of " + Percent.ToString("p");
}
//if population has increased.
if ((startPop < endPop))
{
Percent = ((decimal.Parse(endPop.ToString()) - decimal.Parse(startPop.ToString())) / decimal.Parse(startPop.ToString()));
Message = "Pop. Increase of " + Percent.ToString("p");
}
//if population has not changed.
if ((startPop == endPop))
{
Percent = ((decimal.Parse(endPop.ToString()) - decimal.Parse(startPop.ToString())) / decimal.Parse(startPop.ToString()));
Message = "No Change in Population";
}
}
else
{
MessageBox.Show("Please enter valid population figures.");
}
}
if (int.TryParse(txtDisplayTimes.Text, out dTimes))
{
if (dTimes > 0)
{
lstResults.Items.Clear();
int iSum = 0;
int iLoopCount = dTimes;
//displays the results according to value in txtDisplayTimes.
for (iSum = 1; iSum <= iLoopCount; iSum++)
{
lstResults.Items.Add(Message);
}
}
}
}
}
catch
{
MessageBox.Show("Something went wrong.");
}
}

Application running in ASP.NET is not giving the desired output

I have an application not calculating the percentage correctly. It is suppose to calculate the input in percent. But there is bug somewhere which is preventing it from doing so.
For example, if I input any number starting with decimals like 0.01 or 0.001 or 0.02 etc it will give me the output 1, 0.1 and 2 respectively. If I punch in any whole numbers like 1, 2, 3, 10, etc, it will always give the same output i.e 0.01.
This application was done by some contractors 5 years ago. The main in-charge of this application has left. Which leaves me and my little experience in c# and asp.net in figuring out the issue. Before I seek any further help, I thought I should ask geniuses out there and see what they have to say, may be I will end up figuring out the issue with your help. I did talk to other IT people in my department, they guess it might be because of the code below.
if (int.TryParse(string.IsNullOrEmpty(txtminup.Text) ? "0" : txtminup.Text, out n))
I am not 100% sure how to debug or find the issue. If anyone can point me out anything that might help or provide me some resources that I can look it up, it will be really helpful. I have copied few of the lines of code. I can provide more information but don't know which one will be more relevant.
protected string MinUp
{
get
{
return (string)ViewState["minup"];
}
set
{
ViewState["minup"] = value;
}
}
==============
MinUp = rows["process_minimum_up"].ToString();
PIMSSource = rows["pims_source"].ToString();
//MinUp = Convert.ToDouble()
if (MinUp != string.Empty || MinUp.Length > 0)
{
MinUp = Convert.ToString(Convert.ToDouble(MinUp) * 100);
}
=====================
if (DCFoption != "P")
{
MinUp = "";
}
if (DcfmSeq != "0")
{
int caret;
caret = ddlvbcfmseq.SelectedValue.IndexOf("^");
DcfmSeq = DcfmSeq.Substring(0, caret);
}
if (DCFoption != "P" && ddlpdwnlst.SelectedItem.Value == "0")
{
MinUp = "";
}
if (PIMSTagId == "Not specified")
{
PIMSTagId = "";
}
if (MinUp != string.Empty || MinUp.Length > 0)
{
int n;
if (int.TryParse(string.IsNullOrEmpty(txtminup.Text) ? "0" : txtminup.Text, out n))
{
MinUp = Convert.ToString(Convert.ToInt32(MinUp) / 100);
if (Convert.ToInt32(MinUp) < 0)
{
MinUp = "0";
}
else if (Convert.ToInt32(MinUp) > 1)
{
MinUp = "1";
}
}
}
if ((DCFoption == string.Empty || DCFoption.Length < 1) || DCFoption == "D")
{
MinUp = "";
}
if (MinUp != string.Empty || MinUp.Length > 0)
{
int n;
if (int.TryParse(string.IsNullOrEmpty(txtminup.Text) ? "0" : txtminup.Text, out n))
{
if (Convert.ToDouble(MinUp) <= 0)
{
MinUp = ".0001";
}
}
}
=======================
if (rdbProcess.Checked == true && (txtminup.Text == string.Empty || txtminup.Text.Length < 1) && ddlpdwnlst.SelectedItem.Value == "0")
{
Utilities.ShowAlert(this.Page, Resources.Resource.RIPimsUpload_MinUptime.ToString());
txtminup.Focus();
======================
int n;
if (!int.TryParse(string.IsNullOrEmpty(txtRound.Text) ? "0" : txtRound.Text, out n))
{
Utilities.ShowAlert(this.Page, Resources.Resource.RIPimsUpload_RoundingNum.ToString());
}
else if (!IsDouble(txtminup.Text))
======================
try
{
DBResults objDBResult = new DBResults();
WEIS.RIPimsUpload objRI = new WEIS.RIPimsUpload();
objDBResult = objRI.SaveItemInsert(reciseq, shortname, name, eiscprocess2, period, media, euseq, eqmtseq, eiscuom, pollseq, dcfmseq, rounding, formula, physmin, physmax, warn1min, warn1max, warn2min, warn2max, pimsStatus, pimsTagidp, datapoint, freq, periodoffset, initpimstTagId, initDataPoint, initLoadFrequency, initperiodoffset, day0result, retention, audituser, dcfoption, minup, pimssource);
if (objDBResult.oraErrMsg.Trim().ToString().Length > 1)
{
Exception ex = new Exception(objDBResult.oraErrMsg.ToString());
throw ex;
}
return objDBResult.oraIntReturn;
}
===============================
protected int SaveItemUpdate(int reciseq, string shortname, string name, int eiscprocess2, int period, int media, int euseq, int eqmtseq, int eiscuom, int pollseq, int dcfmseq, string rounding, string formula, string physmin, string physmax, string warn1min, string warn1max, string warn2min, string warn2max, string pimsStatus, string pimsTagidp, string datapoint, string freq, char periodoffset, string initpimstTagId, char initDataPoint, char initLoadFrequency, char initperiodoffset, string day0result, string retention, string audituser, string dcfoption, string minup, string pimssource)
{
try
{
DBResults objDBResult = new DBResults();
WEIS.RIPimsUpload objRI = new WEIS.RIPimsUpload();
objDBResult = objRI.SaveItemUpdate(reciseq, shortname, name, eiscprocess2, period, media, euseq, eqmtseq, eiscuom, pollseq, dcfmseq, rounding, formula, physmin, physmax, warn1min, warn1max, warn2min, warn2max, pimsStatus, pimsTagidp, datapoint, freq, periodoffset, initpimstTagId, initDataPoint, initLoadFrequency, initperiodoffset, day0result, retention, audituser, dcfoption, minup, pimssource);
if (objDBResult.oraErrMsg.Trim().ToString().Length > 1)
{
Exception ex = new Exception(objDBResult.oraErrMsg.ToString());
throw ex;
}
=============================
protected void btnSave_Click(object sender, EventArgs e)
{
try
{
lblUserMsgText.Text = "";
bool dcfm = ddlvbcfmseq.Enabled;
string minup, dcfoption="";
minup = txtminup.Text;
if (rdbNone.Checked == true)
{
dcfoption = "NONE";
}
else if (rdbProcess.Checked == true)
{
dcfoption = "P";
}
else if (rdbData.Checked == true)
{
dcfoption = "D";
}
Index = Convert.ToInt32(rdbListradios.SelectedIndex);
SaveItem();
RetainClientControlValues(dcfm, dcfoption, minup);
}
==============================
protected void btnExcMod_Click(object sender, EventArgs e)
{
try
{
lblUserMsgText.Text = "";
bool dcfm = ddlvbcfmseq.Enabled;
string minup, dcfoption = "";
Index = Convert.ToInt32(rdbListradios.SelectedIndex);
minup = txtminup.Text;
if (rdbNone.Checked == true)
{
dcfoption = "NONE";
}
else if (rdbProcess.Checked == true)
{
dcfoption = "P";
}
else if (rdbData.Checked == true)
{
dcfoption = "D";
}
Button btn = (Button)sender;
int evntseq = Convert.ToInt32(btn.CommandArgument.ToString());
RetainClientControlValues(dcfm, dcfoption, minup);
//Response.Write("you clicked on button");
}
#Umamaheswaran thanks for the hint.
int n;
if (int.TryParse(string.IsNullOrEmpty(txtminup.Text) ? "0" : txtminup.Text, out n))
Above was the initial code and i changed it to
double n;
if (double.TryParse(string.IsNullOrEmpty(txtminup.Text) ? "0" : txtminup.Text, out n))
and also whereever it was converting to
Convert.ToInt32
I changed it to
Convert.ToDouble
I don't know whatever was the issue as I am not very much familiar with asp.net and c# but changing above code solved the issue. Now whenever I input a number it will change to percentage and save it to correct format.
Thank you all for your help and concern. I have few more different issues. I will try to solve it if not I will post it here and try to be concise and to the point.

Matching strings with wildcard

I would like to match strings with a wildcard (*), where the wildcard means "any". For example:
*X = string must end with X
X* = string must start with X
*X* = string must contain X
Also, some compound uses such as:
*X*YZ* = string contains X and contains YZ
X*YZ*P = string starts with X, contains YZ and ends with P.
Is there a simple algorithm to do this? I'm unsure about using regex (though it is a possibility).
To clarify, the users will type in the above to a filter box (as simple a filter as possible), I don't want them to have to write regular expressions themselves. So something I can easily transform from the above notation would be good.
Often, wild cards operate with two type of jokers:
? - any character (one and only one)
* - any characters (zero or more)
so you can easily convert these rules into appropriate regular expression:
// If you want to implement both "*" and "?"
private static String WildCardToRegular(String value) {
return "^" + Regex.Escape(value).Replace("\\?", ".").Replace("\\*", ".*") + "$";
}
// If you want to implement "*" only
private static String WildCardToRegular(String value) {
return "^" + Regex.Escape(value).Replace("\\*", ".*") + "$";
}
And then you can use Regex as usual:
String test = "Some Data X";
Boolean endsWithEx = Regex.IsMatch(test, WildCardToRegular("*X"));
Boolean startsWithS = Regex.IsMatch(test, WildCardToRegular("S*"));
Boolean containsD = Regex.IsMatch(test, WildCardToRegular("*D*"));
// Starts with S, ends with X, contains "me" and "a" (in that order)
Boolean complex = Regex.IsMatch(test, WildCardToRegular("S*me*a*X"));
You could use the VB.NET Like-Operator:
string text = "x is not the same as X and yz not the same as YZ";
bool contains = LikeOperator.LikeString(text,"*X*YZ*", Microsoft.VisualBasic.CompareMethod.Binary);
Use CompareMethod.Text if you want to ignore the case.
You need to add using Microsoft.VisualBasic.CompilerServices; and add a reference to the Microsoft.VisualBasic.dll.
Since it's part of the .NET framework and will always be, it's not a problem to use this class.
For those using .NET Core 2.1+ or .NET 5+, you can use the FileSystemName.MatchesSimpleExpression method in the System.IO.Enumeration namespace.
string text = "X is a string with ZY in the middle and at the end is P";
bool isMatch = FileSystemName.MatchesSimpleExpression("X*ZY*P", text);
Both parameters are actually ReadOnlySpan<char> but you can use string arguments too. There's also an overloaded method if you want to turn on/off case matching. It is case insensitive by default as Chris mentioned in the comments.
Using of WildcardPattern from System.Management.Automation may be an option.
pattern = new WildcardPattern(patternString);
pattern.IsMatch(stringToMatch);
Visual Studio UI may not allow you to add System.Management.Automation assembly to References of your project. Feel free to add it manually, as described here.
A wildcard * can be translated as .* or .*? regex pattern.
You might need to use a singleline mode to match newline symbols, and in this case, you can use (?s) as part of the regex pattern.
You can set it for the whole or part of the pattern:
X* = > #"X(?s:.*)"
*X = > #"(?s:.*)X"
*X* = > #"(?s).*X.*"
*X*YZ* = > #"(?s).*X.*YZ.*"
X*YZ*P = > #"(?s:X.*YZ.*P)"
*X*YZ* = string contains X and contains YZ
#".*X.*YZ"
X*YZ*P = string starts with X, contains YZ and ends with P.
#"^X.*YZ.*P$"
It is necessary to take into consideration, that Regex IsMatch gives true with XYZ, when checking match with Y*. To avoid it, I use "^" anchor
isMatch(str1, "^" + str2.Replace("*", ".*?"));
So, full code to solve your problem is
bool isMatchStr(string str1, string str2)
{
string s1 = str1.Replace("*", ".*?");
string s2 = str2.Replace("*", ".*?");
bool r1 = Regex.IsMatch(s1, "^" + s2);
bool r2 = Regex.IsMatch(s2, "^" + s1);
return r1 || r2;
}
This is kind of an improvement on the popular answer from #Dmitry Bychenko above (https://stackoverflow.com/a/30300521/4491768). In order to support ? and * as a matching characters we have to escape them. Use \\? or \\* to escape them.
Also a pre compiled regex will improve the performance (on reuse).
public class WildcardPattern
{
private readonly string _expression;
private readonly Regex _regex;
public WildcardPattern(string pattern)
{
if (string.IsNullOrEmpty(pattern)) throw new ArgumentNullException(nameof(pattern));
_expression = "^" + Regex.Escape(pattern)
.Replace("\\\\\\?","??").Replace("\\?", ".").Replace("??","\\?")
.Replace("\\\\\\*","**").Replace("\\*", ".*").Replace("**","\\*") + "$";
_regex = new Regex(_expression, RegexOptions.Compiled);
}
public bool IsMatch(string value)
{
return _regex.IsMatch(value);
}
}
usage
new WildcardPattern("Hello *\\**\\?").IsMatch("Hello W*rld?");
new WildcardPattern(#"Hello *\**\?").IsMatch("Hello W*rld?");
To support those one with C#+Excel (for partial known WS name) but not only - here's my code with wildcard (ddd*).
Briefly: the code gets all WS names and if today's weekday(ddd) matches the first 3 letters of WS name (bool=true) then it turn it to string that gets extracted out of the loop.
using System;
using Microsoft.Office.Interop.Excel;
using System.Runtime.InteropServices;
using Range = Microsoft.Office.Interop.Excel.Range;
using System.Diagnostics;
using System.Reflection;
using System.IO;
using System.Text.RegularExpressions;
...
string weekDay = DateTime.Now.ToString("ddd*");
Workbook sourceWorkbook4 = xlApp.Workbooks.Open(LrsIdWorkbook, 0, false, 5, "", "", true, XlPlatform.xlWindows, "\t", false, false, 0, true, 1, 0);
Workbook destinationWorkbook = xlApp.Workbooks.Open(masterWB, 0, false, 5, "", "", true, XlPlatform.xlWindows, "\t", false, false, 0, true, 1, 0);
static String WildCardToRegular(String value)
{
return "^" + Regex.Escape(value).Replace("\\*", ".*") + "$";
}
string wsName = null;
foreach (Worksheet works in sourceWorkbook4.Worksheets)
{
Boolean startsWithddd = Regex.IsMatch(works.Name, WildCardToRegular(weekDay + "*"));
if (startsWithddd == true)
{
wsName = works.Name.ToString();
}
}
Worksheet sourceWorksheet4 = (Worksheet)sourceWorkbook4.Worksheets.get_Item(wsName);
...
public class Wildcard
{
private readonly string _pattern;
public Wildcard(string pattern)
{
_pattern = pattern;
}
public static bool Match(string value, string pattern)
{
int start = -1;
int end = -1;
return Match(value, pattern, ref start, ref end);
}
public static bool Match(string value, string pattern, char[] toLowerTable)
{
int start = -1;
int end = -1;
return Match(value, pattern, ref start, ref end, toLowerTable);
}
public static bool Match(string value, string pattern, ref int start, ref int end)
{
return new Wildcard(pattern).IsMatch(value, ref start, ref end);
}
public static bool Match(string value, string pattern, ref int start, ref int end, char[] toLowerTable)
{
return new Wildcard(pattern).IsMatch(value, ref start, ref end, toLowerTable);
}
public bool IsMatch(string str)
{
int start = -1;
int end = -1;
return IsMatch(str, ref start, ref end);
}
public bool IsMatch(string str, char[] toLowerTable)
{
int start = -1;
int end = -1;
return IsMatch(str, ref start, ref end, toLowerTable);
}
public bool IsMatch(string str, ref int start, ref int end)
{
if (_pattern.Length == 0) return false;
int pindex = 0;
int sindex = 0;
int pattern_len = _pattern.Length;
int str_len = str.Length;
start = -1;
while (true)
{
bool star = false;
if (_pattern[pindex] == '*')
{
star = true;
do
{
pindex++;
}
while (pindex < pattern_len && _pattern[pindex] == '*');
}
end = sindex;
int i;
while (true)
{
int si = 0;
bool breakLoops = false;
for (i = 0; pindex + i < pattern_len && _pattern[pindex + i] != '*'; i++)
{
si = sindex + i;
if (si == str_len)
{
return false;
}
if (str[si] == _pattern[pindex + i])
{
continue;
}
if (si == str_len)
{
return false;
}
if (_pattern[pindex + i] == '?' && str[si] != '.')
{
continue;
}
breakLoops = true;
break;
}
if (breakLoops)
{
if (!star)
{
return false;
}
sindex++;
if (si == str_len)
{
return false;
}
}
else
{
if (start == -1)
{
start = sindex;
}
if (pindex + i < pattern_len && _pattern[pindex + i] == '*')
{
break;
}
if (sindex + i == str_len)
{
if (end <= start)
{
end = str_len;
}
return true;
}
if (i != 0 && _pattern[pindex + i - 1] == '*')
{
return true;
}
if (!star)
{
return false;
}
sindex++;
}
}
sindex += i;
pindex += i;
if (start == -1)
{
start = sindex;
}
}
}
public bool IsMatch(string str, ref int start, ref int end, char[] toLowerTable)
{
if (_pattern.Length == 0) return false;
int pindex = 0;
int sindex = 0;
int pattern_len = _pattern.Length;
int str_len = str.Length;
start = -1;
while (true)
{
bool star = false;
if (_pattern[pindex] == '*')
{
star = true;
do
{
pindex++;
}
while (pindex < pattern_len && _pattern[pindex] == '*');
}
end = sindex;
int i;
while (true)
{
int si = 0;
bool breakLoops = false;
for (i = 0; pindex + i < pattern_len && _pattern[pindex + i] != '*'; i++)
{
si = sindex + i;
if (si == str_len)
{
return false;
}
char c = toLowerTable[str[si]];
if (c == _pattern[pindex + i])
{
continue;
}
if (si == str_len)
{
return false;
}
if (_pattern[pindex + i] == '?' && c != '.')
{
continue;
}
breakLoops = true;
break;
}
if (breakLoops)
{
if (!star)
{
return false;
}
sindex++;
if (si == str_len)
{
return false;
}
}
else
{
if (start == -1)
{
start = sindex;
}
if (pindex + i < pattern_len && _pattern[pindex + i] == '*')
{
break;
}
if (sindex + i == str_len)
{
if (end <= start)
{
end = str_len;
}
return true;
}
if (i != 0 && _pattern[pindex + i - 1] == '*')
{
return true;
}
if (!star)
{
return false;
}
sindex++;
continue;
}
}
sindex += i;
pindex += i;
if (start == -1)
{
start = sindex;
}
}
}
}
C# Console application sample
Command line Sample:
C:/> App_Exe -Opy PythonFile.py 1 2 3
Console output:
Argument list: -Opy PythonFile.py 1 2 3
Found python filename: PythonFile.py
using System;
using System.Text.RegularExpressions; //Regex
namespace ConsoleApp1
{
class Program
{
static void Main(string[] args)
{
string cmdLine = String.Join(" ", args);
bool bFileExtFlag = false;
int argIndex = 0;
Regex regex;
foreach (string s in args)
{
//Search for the 1st occurrence of the "*.py" pattern
regex = new Regex(#"(?s:.*)\056py", RegexOptions.IgnoreCase);
bFileExtFlag = regex.IsMatch(s);
if (bFileExtFlag == true)
break;
argIndex++;
};
Console.WriteLine("Argument list: " + cmdLine);
if (bFileExtFlag == true)
Console.WriteLine("Found python filename: " + args[argIndex]);
else
Console.WriteLine("Python file with extension <.py> not found!");
}
}
}

Select text from a Richtextbox in C#

I want to select the text that is between the last '{' and '}' of a richtextbox text.
I have the next code, but I have an error on the "LastIndexOf" function and I don't know how to fix it. Can someone give me some help?
private void highlightText()
{
mRtbxOperations.SelectionStart = mRtbxOperations.Text.LastIndexOf(#"{", 1, mRtbxOperations.SelectionStart);
mRtbxOperations.SelectionLength = mRtbxOperations.Text.IndexOf(#"}", mRtbxOperations.SelectionStart, mRtbxOperations.Text.Length - 1);
mRtbxOperations.SelectionBackColor = Color.LightBlue;
mRtbxOperations.SelectionFont = new Font(mRtbxOperations.SelectionFont, FontStyle.Underline);
mRtbxOperations.SelectionLength = 0;
}
LastIndexOf Error:
The count must be positive and must refer to a location within the
string, array or collection. Parameter name: count
You LastIndexOf parameters are messed up, as well as the Length of the selection, where you need to substract the starting point in order to get the proper length.
Try a simpler version:
int textStart = mRtbxOperations.Text.LastIndexOf(#"{",
mRtbxOperations.SelectionStart);
if (textStart > -1) {
int textEnd = mRtbxOperations.Text.IndexOf(#"}", textStart);
if (textEnd > -1) {
mRtbxOperations.Select(textStart, textEnd - textStart + 1);
mRtbxOperations.SelectionBackColor = Color.LightBlue;
}
}
Seems that you're getting out of the text bounds. When you are getting a substring or an index, you always should use the string bounds, or a substring bounds. Also, you need to check that the selection is valid.
I would rewrite your code as follows:
private void highlightText()
{
Selection selection = GetSelection(mRtbxOperations.Text);
if (selection == null)
return;
mRtbxOperations.SelectionStart = selection.Start;
mRtbxOperations.SelectionLength = selection.Length;
mRtbxOperations.SelectionBackColor = Color.LightBlue;
mRtbxOperations.SelectionFont = new Font(mRtbxOperations.SelectionFont,
FontStyle.Underline);
}
private static Selection GetSelection(string text)
{
int sIndex = text.LastIndexOf(#"{");
if (sIndex == -1)
return null;
int eIndex = text.IndexOf(#"}", sIndex);
if (eIndex == -1)
return null;
return new Selection(sIndex + 1, eIndex);
}
public class Selection
{
public int Start { get; set; }
public int End { get; set; }
public int Length
{
get
{
return End - Start;
}
}
public Selection(int startIndex, int endIndex)
{
this.Start = startIndex;
this.End = endIndex;
}
}

RichTextBox is finding my search terms in funny places

I'm trying to find instances of a string in a WPF RichTextBox. What I have now almost works, but it highlights the wrong section of the document.
private int curSearchLocation;
private void FindNext_Click(object sender, RoutedEventArgs e)
{
TextRange text = new TextRange(RichEditor.Document.ContentStart, RichEditor.Document.ContentEnd);
var location = text.Text.IndexOf(SearchBox.Text, curSearchLocation, StringComparison.CurrentCultureIgnoreCase);
if (location < 0)
{
location = text.Text.IndexOf(SearchBox.Text, StringComparison.CurrentCultureIgnoreCase);
}
if (location >= 0)
{
curSearchLocation = location + 1;
RichEditor.Selection.Select(text.Start.GetPositionAtOffset(location), text.Start.GetPositionAtOffset(location + SearchBox.Text.Length));
}
else
{
curSearchLocation = 0;
MessageBox.Show("Not found");
}
RichEditor.Focus();
}
This is what happens when I search for "document":
This is because GetPositionAtOffset includes non-text elements such as opening and closing tags in its offset, which is not what I want. I couldn't find a way to ignore these elements, and I also couldn't find a way to directly get a TextPointer to the text I want, which would also solve the problem.
How can I get it to highlight the correct text?
Unfortunately the TextRange.Text strips out non-text characters, so in this case the offset computed by IndexOf will be slightly too low. That is the main problem.
I tried to solve your problem and found working solution that works fine even when we have formatted text in many paragraphs.
A lot of help is taken from this CodeProject Article. So also read that article.
int curSearchLocation;
private void FindNext_Click(object sender, RoutedEventArgs e)
{
TextRange text = new TextRange(RichEditor.Document.ContentStart, RichEditor.Document.ContentEnd);
var location = text.Text.IndexOf(SearchBox.Text, curSearchLocation, StringComparison.CurrentCultureIgnoreCase);
if (location < 0)
{
location = text.Text.IndexOf(SearchBox.Text, StringComparison.CurrentCultureIgnoreCase);
}
if (location >= 0)
{
curSearchLocation = location + 1;
Select(location, SearchBox.Text.Length);
}
else
{
curSearchLocation = 0;
MessageBox.Show("Not found");
}
RichEditor.Focus();
}
public void Select(int start, int length)
{
TextPointer tp = RichEditor.Document.ContentStart;
TextPointer tpLeft = GetPositionAtOffset(tp, start, LogicalDirection.Forward);
TextPointer tpRight = GetPositionAtOffset(tp, start + length, LogicalDirection.Forward);
RichEditor.Selection.Select(tpLeft, tpRight);
}
private TextPointer GetPositionAtOffset(TextPointer startingPoint, int offset, LogicalDirection direction)
{
TextPointer binarySearchPoint1 = null;
TextPointer binarySearchPoint2 = null;
// setup arguments appropriately
if (direction == LogicalDirection.Forward)
{
binarySearchPoint2 = this.RichEditor.Document.ContentEnd;
if (offset < 0)
{
offset = Math.Abs(offset);
}
}
if (direction == LogicalDirection.Backward)
{
binarySearchPoint2 = this.RichEditor.Document.ContentStart;
if (offset > 0)
{
offset = -offset;
}
}
// setup for binary search
bool isFound = false;
TextPointer resultTextPointer = null;
int offset2 = Math.Abs(GetOffsetInTextLength(startingPoint, binarySearchPoint2));
int halfOffset = direction == LogicalDirection.Backward ? -(offset2 / 2) : offset2 / 2;
binarySearchPoint1 = startingPoint.GetPositionAtOffset(halfOffset, direction);
int offset1 = Math.Abs(GetOffsetInTextLength(startingPoint, binarySearchPoint1));
// binary search loop
while (isFound == false)
{
if (Math.Abs(offset1) == Math.Abs(offset))
{
isFound = true;
resultTextPointer = binarySearchPoint1;
}
else
if (Math.Abs(offset2) == Math.Abs(offset))
{
isFound = true;
resultTextPointer = binarySearchPoint2;
}
else
{
if (Math.Abs(offset) < Math.Abs(offset1))
{
// this is simple case when we search in the 1st half
binarySearchPoint2 = binarySearchPoint1;
offset2 = offset1;
halfOffset = direction == LogicalDirection.Backward ? -(offset2 / 2) : offset2 / 2;
binarySearchPoint1 = startingPoint.GetPositionAtOffset(halfOffset, direction);
offset1 = Math.Abs(GetOffsetInTextLength(startingPoint, binarySearchPoint1));
}
else
{
// this is more complex case when we search in the 2nd half
int rtfOffset1 = startingPoint.GetOffsetToPosition(binarySearchPoint1);
int rtfOffset2 = startingPoint.GetOffsetToPosition(binarySearchPoint2);
int rtfOffsetMiddle = (Math.Abs(rtfOffset1) + Math.Abs(rtfOffset2)) / 2;
if (direction == LogicalDirection.Backward)
{
rtfOffsetMiddle = -rtfOffsetMiddle;
}
TextPointer binarySearchPointMiddle = startingPoint.GetPositionAtOffset(rtfOffsetMiddle, direction);
int offsetMiddle = GetOffsetInTextLength(startingPoint, binarySearchPointMiddle);
// two cases possible
if (Math.Abs(offset) < Math.Abs(offsetMiddle))
{
// 3rd quarter of search domain
binarySearchPoint2 = binarySearchPointMiddle;
offset2 = offsetMiddle;
}
else
{
// 4th quarter of the search domain
binarySearchPoint1 = binarySearchPointMiddle;
offset1 = offsetMiddle;
}
}
}
}
return resultTextPointer;
}
int GetOffsetInTextLength(TextPointer pointer1, TextPointer pointer2)
{
if (pointer1 == null || pointer2 == null)
return 0;
TextRange tr = new TextRange(pointer1, pointer2);
return tr.Text.Length;
}
Hope so this code will work for your case.

Categories