Removing part of a String^ in MFC C++ - string

So far I've only written console applications. My first application using MFC (in Visual Studio 2010) is basically a form with two multiline boxes (using String[] arrays noted with String^) and a button to activate text processing. It should search the String^ for a [, look for the ] behind it and delete all characters between them (including the []). With 'normal' C++ strings, this isn't difficult. String^ however is more like an object and MSDN tells me to make use of the Remove method. So, I tried to implement it.
public ref class Form1 : public System::Windows::Forms::Form
{
public:
Form1(void)
{
InitializeComponent();
//
//TODO: Add the constructor code here
//
}
String^ DestroyCoords(String^ phrase)
{
int CoordsStart = 0;
int CoordsEnd = 0;
int CharCount = 0;
for each (Char ch in phrase)
{
if (ch == '[')
CoordsStart = CharCount;
if (ch == ']')
{
CoordsEnd = CharCount;
//CoordsEnd = phrase->IndexOf(ch);
phrase->Remove( CoordsStart , CoordsEnd-CoordsStart );
}
CharCount++;
}
return phrase;
}
The button using the method:
private: System::Void button1_Click(System::Object^ sender, System::EventArgs^ e) {
TempString = String::Copy(BoxInput->Text);
DestroyCoords(TempString);
BoxOutput->Text = TempString;
The function seems to hit the correct places at the correct time, but the phrase->Remove() method is doing absolutely nothing..
I'm no OO hero (as said, I normally only build console applications), so it's probably a rookie mistake. What am I doing wrong?

In C++/CLI, System::String is immutable, so Remove creates a new String^. This means you'll need to assign the results:
phrase = phrase->Remove( CoordsStart , CoordsEnd-CoordsStart );
The same is true in your usage:
TempString = DestroyCoords(TempString);
BoxOutput->Text = TempString;
Note that this will still not work, as you'd need to iterate through your string in reverse (as the index will be wrong after the first removal).

No MFC here, that's the C++/CLI that Microsoft uses for writing .NET programs in C++.
The .NET System::String class is immutable, so any operations you expect to modify the string actually return a new string with the adjustment made.
A further problem is that you're trying to modify a container (the string) while iterating through it. Instead of using Remove, have a StringBuilder variable and copy across the parts of the string you want to keep. This means only a single copy and will be far faster than repeated calls to Remove each of which makes a copy. And it won't interfere with iteration.
Here's the right approach:
int BracketDepth = 0;
StringBuilder sb(phrase->Length); // using stack semantics
// preallocated to size of input string
for each (Char ch in phrase)
{
if (ch == '[') { // now we're handling nested brackets
++BracketDepth;
}
else if (ch == ']') { // and complaining if there are too many closing brackets
if (!BracketDepth--) throw gcnew Exception();
}
else if (!BracketDepth) { // keep what's not brackets or inside brackets
sb.Append(ch);
}
}
if (BracketDepth) throw gcnew Exception(); // not enough closing brackets
return sb.ToString();

Related

Return result of Invoking a Delegate from another thread

I've got a GUI with a TabControl. Each new TabPage is created via a new Thread. I want to call this->tabControl->TabCount, but the tabControl is owned by a thread other than the one I'm calling from. Therefore, I need to Invoke a delegate. However, all the examples I find online show printing to std::cout from each of the delegate methods. I need a return value, in this case an int.
delegate int MyDel();
int InvokeTabCount()
{
if (this->InvokeRequired)
{
MyDel^ del = gcnew MyDel(this, &MyTabControl::InvokeTabCount);
auto temp = this->Invoke(del); // can't just "return this->Invoke(del)"
return temp; // Invoke() returns a System::Object^
}
else
{
return this->tabControl->TabCount;
}
}
void CreateNewTab()
{
// do stuff
this->tabControl->TabPages->Insert(InvokeTabCount() - 1, myNewTab); // insert a tab
this->tabControl->SelectTab(InvokeTabCount() - 2); // OutOfBounds and tabPageNew
}
System::Void MethodToAddNewTabPage() //actually a click event but whatever
{
System::Threading::Thread^ newThread =
gcnew System::Threading::Thread(
gcnew System::Threading::ThreadStart(this, &MyTabControl::CreateNewTab));
newThread->Start();
}
Currently, my InvokeTabCount() method is returning -1 when I simply this->Invoke(del) without returning it. And I am unable to return it because my method expects to return an int instead of a System::Object^ which is what Invoke() returns. However, when debugging I find that auto temp contains the value 2 which is correct. And temp->ToString() contains the value "2" which would also be correct.
How do I return this->Invoke(del)?
Do I need to set the value of a global variable from within my InvokeTabCount() method? I suppose I could find a way to translate from System::String^ to std::string to utilize std::stoi(), but that seems like an odd workaround.
Current solution:
delegate int MyDel();
int InvokeTabCount()
{
if (this->InvokeRequired)
{
MyDel^ del = gcnew MyDel(this, &MyTabControl::InvokeTabCount);
auto temp = this->Invoke(del);
return int::Parse(temp->ToString());
}
else
{
return this->tabControl->TabCount;
}
}
The result is an integer, boxed and contained in an Object^ reference. You should be able to simply cast it to int.
If you want to be extra safe, do a null check and verify that temp->GetType() returns int::typeid, but that's probably overkill since you're creating the delegate (still in the typed form) right there.

Differences between new String and Bytes.toString

I am using hbase utility org.apache.hadoop.hbase.util.Bytes
I generated a an array of Bytes from a string (in a example in Scala):
val bytes = Bytes.toBytes("test")
and want to convert back in String.
What is the difference between new String(bytes,"UTF-8") and Bytes.toString(bytes)
They both works.
At a guess that you are talking about https://hbase.apache.org/apidocs/org/apache/hadoop/hbase/util/Bytes.html, basically nothing: Bytes.toString will call new String, except if the array is empty. You can see the method called here:
public static String toString(final byte [] b, int off, int len) {
if (b == null) {
return null;
}
if (len == 0) {
return "";
}
return new String(b, off, len, UTF8_CHARSET);
}
For the future, please mention any libraries you are using in the question (and the question is completely unrelated to Scala).

BackgroundWorker, can't send other variable other than numeric values to the function callback

Background worker, passing variables are not working, in my example I explain everything, I put only the functions that were important, I have the other functions from the BackgroundWorker.
int TheFunction(unordered_map<std::string,std::string> options, BackgroundWorker^ worker, DoWorkEventArgs ^ e){
if(options["option1"].compare("options") == 0){
//...
}
return 0;
}
void backgroundWorker2_DoWork(Object^ sender, DoWorkEventArgs^ e ){
BackgroundWorker^ worker = dynamic_cast<BackgroundWorker^>(sender);
//e->Result = TheFunction( safe_cast<Int32>(e->Argument), worker, e ); //That's how I do to send an integer value and works just fine, but I don't know how to send non-numeric values with safe_cast or something that works, in the function it looks like this: TheFunction(int index, ...) it works fine, I want to know with unordered_map or with strings also would work, I want more than one argument if you can do with std::string
e->Result = TheFunction(safe_cast<unordered_map<std::string,std::string>>(e->Argument)); //I tried this, and it didn't work
}
void CallBackgroundWorker(){
this->backgroundWorker2 = gcnew System::ComponentModel::BackgroundWorker;
this->backgroundWorker2->WorkerReportsProgress = true;
this->backgroundWorker2->WorkerSupportsCancellation = true;
this->backgroundWorker2->DoWork += gcnew DoWorkEventHandler( this, &GUISystem::backgroundWorker2_DoWork );
this->backgroundWorker2->RunWorkerCompleted += gcnew RunWorkerCompletedEventHandler( this, &GUISystem::backgroundWorker2_RunWorkerCompleted );
this->backgroundWorker2->ProgressChanged += gcnew ProgressChangedEventHandler( this, &GUISystem::backgroundWorker2_ProgressChanged );
unordered_map<std::string,std::string>* options = unordered_map<std::string,std::string>();
options["option1"] = "valor1";
options["option2"] = "valor2";
this->backgroundWorker2->RunWorkerAsync(options);
}
So how do I do to send the unordered_map or a std::string (more than 1 arguments) ?
thanks in advance. that would help a lot.
This line:
unordered_map<std::string,std::string>* options = unordered_map<std::string,std::string>();
isn't legal even in standard C++. A pointer needs to store an address, not an object. So probably you meant to say new to use dynamic allocation (after all, the object needs to survive until the callback runs on the other thread).
At that point, you can wrap the pointer inside System::IntPtr, and in the callback, cast the result of ToPointer().

System.getProperty("line.separator") equivalent in j2me

I need to have a cross-platform newline reference to parse files, and I'm trying to find a way to do the equivalent of the usual
System.getProperty("line.separator");
but trying that in J2ME, I get a null String returned, so I'm guessing line.separator isn't included here. Are there any other direct ways to get a universal newline sequence in J2ME as string?
edit: clarified question a bit
Seems like I forgot to answer my question. I used a piece of code that allowed me to use "\r\n" as delimiter and actually considered \r and \n as well seperately:
public class Tokenizer {
public static String[] tokenize(String str, String delimiter) {
StringBuffer strtok = new StringBuffer();
Vector buftok = new Vector();
char[] ch = str.toCharArray(); //convert to char array
for (int i = 0; i < ch.length; i++) {
if (delimiter.indexOf(ch[i]) != -1) { //if i-th character is a delimiter
if (strtok.length() > 0) {
buftok.addElement(strtok.toString());
strtok.setLength(0);
}
}
else {
strtok.append(ch[i]);
}
}
if (strtok.length() > 0) {
buftok.addElement(strtok.toString());
}
String[] splitArray = new String[buftok.size()];
for (int i=0; i < splitArray.length; i++) {
splitArray[i] = (String)buftok.elementAt(i);
}
buftok = null;
return splitArray;
}
}
I don't think "line.separator" is a system property of JME. Take a look at this documentation at SDN FAQ for MIDP developers: What are the defined J2ME system property names?
Why do you need to get the line separator anyway? What I know is that you can use "\n" in JME.

Console application: How to update the display without flicker?

Using C# 4 in a Windows console application that continually reports progress how can I make the "redraw" of the screen more fluid?
I'd like to do one of the following:
- Have it only "redraw" the part of the screen that's changing (the progress portion) and leave the rest as is.
- "Redraw" the whole screen but not have it flicker.
Currently I re-write all the text (application name, etc.). Like this:
Console.Clear();
WriteTitle();
Console.WriteLine();
Console.WriteLine("Deleting:\t{0} of {1} ({2})".FormatString(count.ToString("N0"), total.ToString("N0"), (count / (decimal)total).ToString("P2")));
Which causes a lot of flickering.
Try Console.SetCursorPosition. More details here: How can I update the current line in a C# Windows Console App?
static void Main(string[] args)
{
Console.SetCursorPosition(0, 0);
Console.Write("################################");
for (int row = 1; row < 10; row++)
{
Console.SetCursorPosition(0, row);
Console.Write("# #");
}
Console.SetCursorPosition(0, 10);
Console.Write("################################");
int data = 1;
System.Diagnostics.Stopwatch clock = new System.Diagnostics.Stopwatch();
clock.Start();
while (true)
{
data++;
Console.SetCursorPosition(1, 2);
Console.Write("Current Value: " + data.ToString());
Console.SetCursorPosition(1, 3);
Console.Write("Running Time: " + clock.Elapsed.TotalSeconds.ToString());
Thread.Sleep(1000);
}
Console.ReadKey();
}
I know this question is a bit old but I found if you set Console.CursorVisible = false then the flickering stops as well.
Here's a simple working demo that shows multi-line usage without flickering. It shows the current time and a random string every second.
private static void StatusUpdate()
{
var whiteSpace = new StringBuilder();
whiteSpace.Append(' ', 10);
var random = new Random();
const string chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
var randomWord = new string(Enumerable.Repeat(chars, random.Next(10)).Select(s => s[random.Next(s.Length)]).ToArray());
while (true)
{
Console.SetCursorPosition(0, 0);
var sb = new StringBuilder();
sb.AppendLine($"Program Status:{whiteSpace}");
sb.AppendLine("-------------------------------");
sb.AppendLine($"Last Updated: {DateTime.Now}{whiteSpace}");
sb.AppendLine($"Random Word: {randomWord}{whiteSpace}");
sb.AppendLine("-------------------------------");
Console.Write(sb);
Thread.Sleep(1000);
}
}
The above example assumes your console window is blank to start. If not, make sure to use Console.Clear() first.
Technical Note:
SetCursorPosition(0,0) places the cursor back to the top (0,0) so the next call to Console.Write will start from line 0, char 0. Note, it doesn't delete the previous content before writing. As an example, if you write "asdf" over a previous line such as "0123456", you'll end up with something like "asdf456" on that line. For that reason, we use a whiteSpace variable to ensure any lingering characters from the previous line are overwritten with blank spaces. Adjust the length of the whiteSpace variable to meet your needs. You only need the whiteSpace variable for lines that change.
Personal Note:
For my purposes, I wanted to show the applications current status (once a second) along with a bunch of other status information and I wanted to avoid any annoying flickering that can happen when you use Console.Clear(). In my application, I run my status updates behind a separate thread so it constantly provides updates even though I have numerous other threads and long running tasks going at the same time.
Credits:
Thanks to previous posters and dtb for the random string generator used in the demo.
How can I generate random alphanumeric strings in C#?
You could try to hack something together using the core libraries.
Rather than waste your time for sub-standard results, I would check out this C# port of the ncurses library (which is a library used for formatting console output):
Curses Sharp
I think you can use \r in Windows console to return the beginning of a line.
You could also use SetCursorPosition.
I would recommend the following extension methods. They allow you to use a StringBuilder to refresh the console view without any flicker, and also tidies up any residual characters on each line
The Problem: The following demo demonstrates using a standard StringBuilder, where updating lines that are shorter than the previously written line get jumbled up. It does this by writing a short string, then a long string on a loop:
public static void Main(string[] args)
{
var switchTextLength = false;
while(true)
{
var sb = new StringBuilder();
if (switchTextLength)
sb.AppendLine("Short msg");
else
sb.AppendLine("Longer message");
sb.UpdateConsole();
switchTextLength = !switchTextLength;
Thread.Sleep(500);
}
}
Result:
The Solution: By using the extension method provided below, the issue is resolved
public static void Main(string[] args)
{
var switchTextLength = false;
while(true)
{
var sb = new StringBuilder();
if (switchTextLength)
sb.AppendLineEx("Short msg");
else
sb.AppendLineEx("Longer message");
sb.UpdateConsole();
switchTextLength = !switchTextLength;
Thread.Sleep(500);
}
}
Result:
Extension Methods:
public static class StringBuilderExtensions
{
/// <summary>
/// Allows StrinbBuilder callers to append a line and blank out the remaining characters for the length of the console buffer width
/// </summary>
public static void AppendLineEx(this StringBuilder c, string msg)
{
// Append the actual line
c.Append(msg);
// Add blanking chars for the rest of the buffer
c.Append(' ', Console.BufferWidth - msg.Length - 1);
// Finish the line
c.Append(Environment.NewLine);
}
/// <summary>
/// Combines two StringBuilders using AppendLineEx
/// </summary>
public static void AppendEx(this StringBuilder c, StringBuilder toAdd)
{
foreach (var line in toAdd.ReadLines())
{
c.AppendLineEx(line);
}
}
/// <summary>
/// Hides the console cursor, resets its position and writes out the string builder
/// </summary>
public static void UpdateConsole(this StringBuilder c)
{
// Ensure the cursor is hidden
if (Console.CursorVisible) Console.CursorVisible = false;
// Reset the cursor position to the top of the console and write out the string builder
Console.SetCursorPosition(0, 0);
Console.WriteLine(c);
}
}
I actually had this issue so I made a quick simple method to try and eliminate this.
static void Clear(string text, int x, int y)
{
char[] textChars = text.ToCharArray();
string newText = "";
//Converts the string you just wrote into a blank string
foreach(char c in textChars)
{
text = text.Replace(c, ' ');
}
newText = text;
//Sets the cursor position
Console.SetCursorPosition(x, y);
//Writes the blank string over the old string
Console.WriteLine(newText);
//Resets cursor position
Console.SetCursorPosition(0, 0);
}
It actually worked surprisingly well and I hope it may work for you!
Naive approach but for simple applications is working:
protected string clearBuffer = null; // Clear this if window size changes
protected void ClearConsole()
{
if (clearBuffer == null)
{
var line = "".PadLeft(Console.WindowWidth, ' ');
var lines = new StringBuilder();
for (var i = 0; i < Console.WindowHeight; i++)
{
lines.AppendLine(line);
}
clearBuffer = lines.ToString();
}
Console.SetCursorPosition(0, 0);
Console.Write(clearBuffer);
Console.SetCursorPosition(0, 0);
}
Console.SetCursorPosition(0, 0); //Instead of Console.Clear();
WriteTitle();
Console.WriteLine();
Console.WriteLine("Deleting:\t{0} of {1} ({2})".FormatString(count.ToString("N0")

Resources