Author Topic: How can I parse a text string with a delimiter into variables?  (Read 3338 times)

Boston

  • Newbie
  • *
  • Posts: 18
How can I parse a text string with a delimiter into variables?
« on: January 23, 2023, 08:50:16 PM »
How can I parse a text string with a delimiter into variables?

Example with space delimiter. After reading a text file one row returned:
121.1 0 kbtv_app.pls

121.1 - needs to be a decimal variable
0 - needs to be an integer variable
kbtv_app.pls - needs to be a text variable

I thought this would not be hard but after days of looking I have learned a lot... (my best hope "TXTSEGMENT" does not exist yet). Sorry if this is a newbie question. I only know enough to get hopelessly lost apparently.

Pfeil

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 4781
  • RTFM
Re: How can I parse a text string with a delimiter into variables?
« Reply #1 on: January 23, 2023, 09:11:08 PM »
While this can be done using native actions, that's not a particularly practical option (as you mention, there is currently no token to retrieve part of a text value, meaning you'd need to "manually" parse the string).

Assuming that your input data is consistent (I.E. it always has at least two delimiters, and the values can be converted into the datatypes you've mentioned), an inline function like this could work:
Code: [Select]
public class VAInline
{
public void main()
{
string[] substrings = VA.GetText("my input text variable").Split(' ');
VA.SetDecimal("my output decimal variable", decimal.Parse(substrings[0]));
VA.SetInt("my output integer variable", int.Parse(substrings[1]));
VA.SetText("my output text variable", substrings[2]);
}
}

Boston

  • Newbie
  • *
  • Posts: 18
Re: How can I parse a text string with a delimiter into variables?
« Reply #2 on: January 24, 2023, 09:35:26 AM »
First Pfeil, Thank you. The C# code looks remarkably, simply elegant!

Can not confirm your code yet. RL snow must be moved :(  I will report back, however.

By "Manually" you mean character by character right?

I figured out you're returning a row from a text file C#, so this should not be too bad. It will be now my second foray into C#. returning a row from a text file was my first.  I am an architect so this code stuff is not natural for me. A different side of the brain maybe.

Again, thank you very much.

Boston

  • Newbie
  • *
  • Posts: 18
Re: How can I parse a text string with a delimiter into variables?
« Reply #3 on: January 24, 2023, 11:01:36 AM »
It works for decFreq and intRange but not txtStreamFile.

Set decimal [decFreq] value to 1.1 (save value to profile)
Set integer [intRange] value to 1 (save value to profile)
Set text [txtStreamFile] to 'hello world' (save value to profile)

using System;

public class VAInline
{
   public void main()
   {

      string[] substrings = VA.GetText("~lineOutput").Split(' ');
      VA.SetDecimal("decFreq", decimal.Parse(substrings[0]));
      VA.SetInt("intRange", int.Parse(substrings[1]));
      VA.SetText("txtStreamFile", substrings[2]);

   }
}

The Inline Function C# Code Test Run: Exception has been thrown by the target of an invocation. Object reference not set to an instance of an object.

Results in VoiceAttack window before and after Write a Value to the Event Log:

Write '{DEC:decFreq}' to log
Write '{INT:intRange}' to log
Write '{TXT:txtStreamFile}' to log

and after...

Write '"{TXT:~lineOutput}"' to log
Write '{DEC:decFreq}' to log
Write '{INT:intRange}' to log
Write '{TXT:txtStreamFile}' to log

12:50:12.168 hello world
12:50:12.166 0
12:50:12.164 121.1
12:50:11.978 "121.1 0 kbtv_app.pls"
12:50:11.883 hello world
12:50:11.881 1
12:50:11.879 1.1
12:50:11.869 Recognized : 'com swap'

I tried playing with the line:

VA.SetText("txtStreamFile", substrings[2]);

including adding text.parse including parentheses but no luck.

"hello world" should have changed to "kbtv_app.pls".  Do you think "_" or "." caused a problem as part of a text string?

EricM

  • Newbie
  • *
  • Posts: 15
  • VA user since 2017
Re: How can I parse a text string with a delimiter into variables?
« Reply #4 on: January 24, 2023, 01:06:13 PM »
I bet the value does change if you put a plain string in there e.g. VA.SetText("txtStreamFile", "kbtv_app.pls");

If that's the case then there's probably some invisible return characters at the end of your ~lineOutput variable's text that the VA.SetText() function doesn't like.

I'm not sure if my syntax is correct, but something like this might work:
Code: [Select]
VA.SetText("txtStreamFile", substrings[2].Split('\n')[0]);

Pfeil

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 4781
  • RTFM
Re: How can I parse a text string with a delimiter into variables?
« Reply #5 on: January 24, 2023, 07:03:21 PM »
Newline characters are just characters. They have no special significance within a string variable.


The Inline Function C# Code Test Run: Exception has been thrown by the target of an invocation. Object reference not set to an instance of an object.
Yes, if you use the "Test Run" button, that command-scoped variable won't exist, and as such the String.Split() method won't have anything to work with


Make sure to enable (check) the "Wait for the inline function to finish before continuing" option for the inline functions you're using

Boston

  • Newbie
  • *
  • Posts: 18
Re: How can I parse a text string with a delimiter into variables?
« Reply #6 on: January 24, 2023, 08:29:12 PM »
I bet the value does change if you put a plain string in there e.g. VA.SetText("txtStreamFile", "kbtv_app.pls");

If that's the case then there's probably some invisible return characters at the end of your ~lineOutput variable's text that the VA.SetText() function doesn't like.

I'm not sure if my syntax is correct, but something like this might work:
Code: [Select]
VA.SetText("txtStreamFile", substrings[2].Split('\n')[0]);

Thank you.  It did not work but I can try other syntaxes.

Boston

  • Newbie
  • *
  • Posts: 18
Re: How can I parse a text string with a delimiter into variables?
« Reply #7 on: January 24, 2023, 08:31:55 PM »

Make sure to enable (check) the "Wait for the inline function to finish before continuing" option for the inline functions you're using

Thank you. "Wait for the inline function to finish before continuing" was checked. Any other direction I should investigate?  I don't mind looking because I learn so much as I go.

Pfeil

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 4781
  • RTFM
Re: How can I parse a text string with a delimiter into variables?
« Reply #8 on: January 24, 2023, 08:34:24 PM »
What does your command look like at this point?

Right-click the action list, choose "Copy All as Text" from the context menu, then paste here into a code block (click the # button)

Boston

  • Newbie
  • *
  • Posts: 18
Re: How can I parse a text string with a delimiter into variables?
« Reply #9 on: January 24, 2023, 09:29:53 PM »
Code: [Select]
Set decimal [decFreq] value to 1.1 (save value to profile)
Set integer [intRange] value to 1 (save value to profile)
Set decimal [decLat] value to 1.2 (save value to profile)
Set decimal [decLong] value to 1.3 (save value to profile)
Set text [txtStreamFile] to 'hello world' (save value to profile)
Write [Blue] '{DEC:decFreq}' to log
Write [Blue] '{INT:intRange}' to log
Write [Blue] '{DEC:decLat}' to log
Write [Blue] '{DEC:decLong}' to log
Write [Blue] '{TXT:txtStreamFile}' to log
Set text [~textFile] to [C:\MSFS Utl\BostonRadio\Boston Radio Freq.txt]
Set integer [~targetLine] value to 2
Inline C# Function: , wait until execution finishes
Inline C# Function: , wait until execution finishes
Set text [txtStreamFile] to [Saved Value] (save value to profile)
Write [Blue] '"{TXT:~lineOutput}"' to log
Write [Blue] '{DEC:decFreq}' to log
Write [Blue] '{INT:intRange}' to log
Write [Blue] '{DEC:decLat}' to log
Write [Blue] '{DEC:decLong}' to log
Write [Blue] '{TXT:txtStreamFile}' to log

Inline C# Function: , wait until execution finishes (First one)
Code: [Select]
using System;


public class VAInline
{
public void main()
{

string input = VA.GetText("~textFile");
if (input == null)
{
VA.WriteToLog("Cannot get line, no file set", "red");
return;
}

int targetLine = VA.GetInt("~targetLine") ?? -1;
if (targetLine < 1)
{
VA.WriteToLog("Cannot get line, no or invalid line number set", "red");
return;
}

string[] lines = input.Split(new[] {Environment.NewLine}, StringSplitOptions.None);

if (targetLine > lines.Length)
{
VA.WriteToLog("Warning: Target line is " + targetLine + ", but the file only contains " + lines.Length + " lines", "orange");
return;
}

VA.SetText("~lineOutput", lines[targetLine - 1]);

/*
string[] substrings = VA.GetText("~lineOutput").Split(' ');
VA.SetDecimal("decFreq", decimal.Parse(substrings[0]));
VA.SetInt("intRange", int.Parse(substrings[1]));
VA.SetText("txtStreamFile", substrings[2]);
*/

}
}

Inline C# Function: , wait until execution finishes (second one)
Code: [Select]
using System;

public class VAInline
{
public void main()
{

string[] substrings = VA.GetText("~lineOutput").Split(' ');
VA.SetDecimal("decFreq", decimal.Parse(substrings[0]));
VA.SetInt("intRange", int.Parse(substrings[1]));
VA.SetDecimal("decLat", decimal.Parse(substrings[2]));
VA.SetDecimal("decLong", decimal.Parse(substrings[3]));
VA.SetText("txtStreamFile", substrings[4]);

// VA.SetText("txtStreamFile", substrings[2].Split('\n')[0]);


}
}

Sample Boston Radio Freq.txt
Code: [Select]
120.35 0 zbw_mpv.pls
121.1 0 kbtv_app.pls
123.75 0 zbw_gdm.pls
124.85 0 kbdl2_zbw_pvd_low.pls
124.9 0 kmht_murp_fitzy.pls
126.1 0 kack_app.pls
128.2 0 zbw_parso.pls
128.325 0 kalb1_zbw_cam39.pls
132.85 0 cyul_app.pls
134.7 0 zbw_con.pls
135.7 0 zbw_mpv.pls

125.1 1 42.79277778 71.52361111 kash_atis.pls
121.8 1 42.79277778 71.52361111 kash4_gnd.pls
133.2 1 42.79277778 71.52361111 kash4_twr.pls

Pfeil

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 4781
  • RTFM
Re: How can I parse a text string with a delimiter into variables?
« Reply #10 on: January 24, 2023, 09:34:16 PM »
...you're overwriting the value of "txtStreamFile" with the value you've previously set it to (which you saved to the profile)

Do you understand what the "Save value to profile" option does?

Boston

  • Newbie
  • *
  • Posts: 18
Re: How can I parse a text string with a delimiter into variables?
« Reply #11 on: January 24, 2023, 09:44:19 PM »

Do you understand what the "Save value to profile" option does?

Sorry, rereading. I did disable:
Set text [txtStreamFile] to [Saved Value] (save value to profile)
with the same result:

11:42:41.813 hello world
11:42:41.811 1.3
11:42:41.809 1.2
11:42:41.807 0
11:42:41.805 121.1
11:42:41.803 "121.1 0 kbtv_app.pls"
11:42:41.787 Inline function execution exception: Exception has been thrown by the target of an invocation. Input string was not in a correct format.
11:42:41.526 hello world
11:42:41.519 1.3
11:42:41.517 1.2
11:42:41.514 1
11:42:41.512 1.1
11:42:41.374 Recognized : 'com swap'

Pfeil

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 4781
  • RTFM
Re: How can I parse a text string with a delimiter into variables?
« Reply #12 on: January 24, 2023, 09:50:28 PM »
As the log mentions, an exception is getting thrown. In this case because a conversion is being attempted on an invalid value.

You're passing in "121.1 0 kbtv_app.pls", splitting that, and then attempting to convert the substring at index 2 of the resulting array to a decimal value.
"kbtv_app.pls" is not a valid decimal value.

Boston

  • Newbie
  • *
  • Posts: 18
Re: How can I parse a text string with a delimiter into variables?
« Reply #13 on: January 24, 2023, 09:58:00 PM »
Do you understand what the "Save value to profile" option does?

It works. Thank you. I thought "Save value to profile" was used to save within the profile so other commands could access the data.  Removed all "Save value to profile".  Not sure why decimals and integers were not affected. Will think about it awhile I am sure.

Boston

  • Newbie
  • *
  • Posts: 18
Re: How can I parse a text string with a delimiter into variables?
« Reply #14 on: January 25, 2023, 07:30:20 AM »
Thank you for your direction and coding!

You're passing in "121.1 0 kbtv_app.pls", splitting that, and then attempting to convert the substring at index 2 of the resulting array to a decimal value.
"kbtv_app.pls" is not a valid decimal value.

In my rush to test I did forget to respond to this point last night. You are absolutely right. I was grabbing sample data quickly and grabbed the wrong set. This set was when I was transitioning from 3 data points per row to 5. The current data set has - 120.35 0 0 0 zbw_mpv.pls.

Question. I am thinking of sometimes adding a 6th data point to a row. A text variable that most likely contains more than one word with of course spaces. Do you think adding an underscore(s) in the 6th data point instead of space(s) to make retrieving the data easier, then replacing the underscore(s) with space(s) for the TTS engine is the easiest way?

Again thank you.

Pfeil

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 4781
  • RTFM
Re: How can I parse a text string with a delimiter into variables?
« Reply #15 on: January 25, 2023, 07:40:31 AM »
I am thinking of sometimes adding a 6th data point to a row. A text variable that most likely contains more than one word with of course spaces. Do you think adding an underscore(s) in the 6th data point instead of space(s) to make retrieving the data easier, then replacing the underscore(s) with space(s) for the TTS engine is the easiest way?
If you have the option to use underscores rather than spaces when writing that text to the file, that is likely the simplest option in this scenario, yes.

Boston

  • Newbie
  • *
  • Posts: 18
Re: How can I parse a text string with a delimiter into variables?
« Reply #16 on: February 06, 2023, 03:31:31 AM »
I am almost done except...

I started with text variable txtPOI;
Test_POI

so the "Say" command does not say "underscore" I want to convert to;
Test POI

Found this (Topic: Multiple Variable Command) your reply;
Set Text [consoleCommand] to 'ChangeLevel {TXT:consoleCommand}_{TXTREPLACEVAR:"{CMDSEGMENT:2}":" ":"_"}'
and looked at the VoiceAttackHelp.pdf page 160, so I tried this;
Code: [Select]
Set text [txtPOIclean] to '{TXTREPLACEVAR:txtPOI:" ":"_"}'
with these varations;
{TXTREPLACEVAR:txtPOI:" ":"_"}
{TXTREPLACEVAR:txtPOI:"_":" "}
{TXTREPLACEVAR:"txtPOI":"_":" "}
{TXTREPLACEVAR:{txtPOI}:"_":" "}
{TXTREPLACEVAR:"{txtPOI}":"_":" "}
{TXTREPLACEVAR:{TXT:txtPOI}:"_":" "}
{TXTREPLACEVAR:"{TXT:txtPOI}":"_":" "}

(huge exhale) what syntax am I missing?

Pfeil

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 4781
  • RTFM
Re: How can I parse a text string with a delimiter into variables?
« Reply #17 on: February 06, 2023, 11:36:57 AM »
The second variation you tried should have worked.

E.G.
Code: [Select]
Set text [txtPOI] to 'Test_POI'
Set text [txtPOIclean] to '{TXTREPLACEVAR:txtPOI:"_":" "}'
Write [Blue] '{TXT:txtPOIclean}' to log

Though, using a token is unnecessary given that the "Set a Text Value" action now has a "Replace with" option:
Code: [Select]
Set text [txtPOIclean] to [txtPOI] (Replace '_' with ' ')

If you don't need "txtPOI" to contain the underscore, you could instead consider performing the replacement within the inline function, E.G.
Code: [Select]
VA.SetText("txtStreamFile", substrings[4].Replace('_', ' '));

Pfeil

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 4781
  • RTFM
Re: How can I parse a text string with a delimiter into variables?
« Reply #18 on: February 06, 2023, 12:46:17 PM »
Take a moment to examine your command:
Code: [Select]
Begin Decimal Compare : [txtPOI] Does Not Equal [a]
What datatype are you comparing, and what datatype are you intending to compare?

Also, if you put a literal value in a field labeled "Another Variable", how will that value be interpreted?

Boston

  • Newbie
  • *
  • Posts: 18
Re: How can I parse a text string with a delimiter into variables?
« Reply #19 on: February 06, 2023, 01:05:37 PM »
Sorry I deleted my post the instant I figured it out.  You are VERY fast!!!

Code: [Select]
VA.SetText("txtStreamFile", substrings[4].Replace('_', ' '));

Works GREAT! Very elegant.

My text file has more than 300 lines. I was thinking a relational database would be quicker. The only VoiceAttack Forum post I found was about creating DLLs. Is there somewhere to look for an example going against an Access DB? Maybe split it into 5 text files and scan them simultaneously.

BTW
Code: [Select]
Begin Text Compare : [txtPOI] Equals 'a'
« Last Edit: February 06, 2023, 08:24:15 PM by Boston »

Pfeil

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 4781
  • RTFM
Re: How can I parse a text string with a delimiter into variables?
« Reply #20 on: February 08, 2023, 02:53:59 PM »
300 lines shouldn't take much time at all to parse, assuming it's all done within an inline function. Chances are your current command is structured inefficiently for that task you're having it perform.

Multiple text files would take more time, not less, if you're doing everything synchronously.