Replace token's text in ANTLR - c#

I'm trying to replace some token's text from my input program to a specific formated text. I'm using C# as output language.
Example of input:
time#1m2s
My lex grammar for that input:
fragment
DIGIT : '0'..'9'
;
CTE_DURATION
: ('T'|'t'|'TIME'|'time') '#' '-'? (DIGIT ('d'|'h'|'m'|'s'|'ms') '_'?)+
;
Output token text I'd like to get from input example:
0.0:1:2.0
That's means: 0 days, 0 hours, 1 minute, 2 seconds and 0 milliseconds.
Any advice? Thank you in advance.

Here's a way to do that (it's in Java, but shouldn't be hard to port to C#):
grammar Test;
parse
: CTE_DURATION EOF
;
CTE_DURATION
: ('T' 'IME'? | 't' 'ime'?) '#' minus='-'?
(d=DIGITS 'd')? (h=DIGITS 'h')? (m=DIGITS 'm')? (s=DIGITS 's')? (ms=DIGITS 'ms')?
{
int days = $d == null ? 0 : Integer.valueOf($d.text);
int hours = $h == null ? 0 : Integer.valueOf($h.text);
int minutes = $m == null ? 0 : Integer.valueOf($m.text);
int seconds = $s == null ? 0 : Integer.valueOf($s.text);
int mseconds = $ms == null ? 0 : Integer.valueOf($ms.text);
setText(($minus == null ? "" : "-") + days + "." + hours + ":" + minutes + ":" + seconds + "." + mseconds);
}
;
fragment DIGITS : '0'..'9'+;
Parsing the input time#1m2s results in the following parse tree:
Note that the grammar now accepts time# as well (causing it to produce 0.0:0:0.0), but you can easily produce an exception from the lexer rule in case such input is invalid.

Related

Removing chars on every line of string (C#)

So I'm currently trying to remove the following chars: "# " (With the space) It kinda works, because I have 3 lines, and it removes it on the first line. Here is my code:
string serverInfo = "Connected to 74.91.119.188:27015\n" +
"hostname:[FN] 24 / 7 Surf Utopia | Styles | !KNIFE,!WS,!GLOVES\n" +
"version: 1.37.9.5 secure\n" +
"os : Linux\n" +
"type : community dedicated\n" +
"map: surf_utopia_v3\n" +
"players : 24 humans, 0 bots(64 / 0 max)(not hibernating)\n" +
"# userid name uniqueid connected ping loss state rate\n" +
"# 3785 1 \"Con\" STEAM_1:0:128083116 03:13 32 0 active 196608\n" +
"# 3786 2 \"yolo\" STEAM_1:0:172863146 03:13 171 0 active 196608\n" +
"# 3787 3 \"chodyツ\" STEAM_1:0:42129452 03:13 46 0 active 786432\n" +
"#end\n";
var removeEnd = serverInfo.IndexOf("#end");
var newString = serverInfo.Remove(removeEnd);
var firstHashTag = newString.IndexOf("#");
var secondHashTag = newString.IndexOf("#", firstHashTag + 1);
var final = newString.Substring(secondHashTag);
if (final.Contains("# "))
{
var index = final.IndexOf("# ");
var newFinal = final.Substring(index + 2);
Console.WriteLine(newFinal);
}
Console.ReadLine();
Here is the output:
My question is:
How can I apply this to every line, I don't know how many lines there will be, all I know is that I need to remove "# " from every line there might be. (I don't know how many there will be, this is just for practice)
So you want to remove all occurrences of "# "? Why don't you just use
string newString = serverInfo.Replace("# ","");
This outputs:
Connected to 74.91.119.188:27015
hostname:[FN] 24 / 7 Surf Utopia | Styles | !KNIFE,!WS,!GLOVES
version: 1.37.9.5 secure
os : Linux
type : community dedicated
map: surf_utopia_v3
players : 24 humans, 0 bots(64 / 0 max)(not hibernating)
userid name uniqueid connected ping loss state rate
3785 1 "Con" STEAM_1:0:128083116 03:13 32 0 active 196608
3786 2 "yolo" STEAM_1:0:172863146 03:13 171 0 active 196608
3787 3 "chodyツ" STEAM_1:0:42129452 03:13 46 0 active 786432
#end
If you want to do something on a string line by line you should use System.IO.StringReader class:
using (StringReader reader = new StringReader(yourMultiLineString)
{
while((line = reader.ReadLine()) != null){
string line = reader.ReadLine();
//do something on line here
}
}
That's it, I left the implementation code to you.
Here is the code solution for your problem. Keep looping and removing until the index of remove string is -1. Keep in mind that the function "Replace" works on the first value it finds.
var textToRemove = "#end";
while(serverInfo.IndexOf(textToRemove) > -1)
{
serverInfo = serverInfo.Replace(textToRemove, string.Empty);
}

Input string was not in a correct format. C# SQL

I am putting SQL values inside <td> and this line below it's causing a format error, i don't know if the parsing is incorrect or missing something. Please help
litAccordionFooter.Text += "<td style='width: 12.2%;font-weight: bold;'>"
+ string.Format("{0:C}", (((ds.Tables[1].Rows[0]["TOTAL_AMT"]))
== DBNull.Value ? 1
: decimal.Parse((ds.Tables[1].Rows[0]["TOTAL_AMT"]).ToString()))
/ ((int.Parse((ds.Tables[1].Rows[0]["TOTAL_QTY"]).ToString())) == 0
|| ds.Tables[1].Rows[0]["TOTAL_QTY"] == DBNull.Value ? 1
: (int.Parse((ds.Tables[1].Rows[0]["TOTAL_QTY"]).ToString())))) + "</td>";
As #JoãoKleberson says, you should validate they are not null or empty and that they have actually a int and decimal representation
int total_Amt = default(int);
decimal total_Qty = default(decimal);
if (decimal.TryParse(ds.Tables[1].Rows[0]["TOTAL_AMT"].ToString(), out total_Qty) &&
int.TryParse(ds.Tables[1].Rows[0]["TOTAL_QTY"].ToString(), out total_Amt))
{
var myString = "<td style='width: 12.2%;font-weight:bold;'>" +
string.Format("{0:C}", total_Amt / total_Qty == 0 ? 1 : total_Qty) + "</td>";
}
else
{
// The TOTAL_AMT and/or TOTAL_QTY values are not valid to convert them,
// verify they are not null and that they have the correct format
}
This way you can safety try to convert the values to the desired type, if the can't be converted the flow is going to be to the else clause
Make sure this statement:
(ds.Tables [1] .Rows [0] ["TOTAL_AMT"])
(ds.Tables [1] .Rows [0] ["TOTAL_QTY"])
It is not null or empty

Format custom numeric string with fixed character count

I need to convert any number in a fixed format with a fixed amount of characters. Means 1500 and -1.5 or 0.025 need to have the same length. I also have to give the format in this form: Format = "{???}";
When i type Format = "{0000}"; i can limit 1500 to "1500", but -1.5 -> "-0001.5" means i have too much numbers after the point.
Negative sign place can be done with Format = "{ 0.0;-0.0; 0.0}".
How can i fix the count of the numbers for different numbers?
The length of the string doesn't matter, the most important is the equal length.
Examples:
1500 -> " 1500.000" or " 1500"
-1500 -> "-1500.000" or "- 1500" or " -1500"
1.5 -> " 1.500" or " 1.5"
-0.25-> " -0.250" or "- 0.25"
0.00005 -> " 0.000" or " 0"
150000-> " 150000.0" or " 150000"
15000000 " 15000000"
Edit:
I want to Format an y-Axis of a Chart. I can't use something like value.ToString("???") i need to use chartArea.AxisY.LabelStyle.Format = "{???}";
Why don't use formatting? "F3" forces 3 digits after decimal point and PadLeft ensures the overall length
Double value = 1500.0;
// 3 digits after decimal point, 9 characters length
String result = value.ToString("F3").PadLeft(9, ' ');
0 -> 0.000
1500.0 -> 1500.000
-1500.0 -> -1500.000
-0.25 -> -0.250
Another (similar) possibility is String.Format:
Double value = 1500.0;
// Put value at place {0} with format "F4" aligned to right up to 9 symbols
String result = String.Format("{0:9,F4}", value);
Try it > result = Math.Round(yourValue, 3);
Check full reference here !
you cannot achieve this by a simple format function
string result = string.Empty;
var array = dec.ToString().Split('.');
if (dec > 0)
{
result = array[0].PadLeft(9).Remove(0, 9);
if (array.Count() > 1)
{
result += '.' + array[1].PadRight(3).Remove(3);
}
}
else
{
result = "-"+array[0].PadLeft(9).Remove(0, 9);
if (array.Count() > 1)
{
result += '.' + array[1].PadRight(3).Remove(3);
}
}

Character Textfile to binary Textfile

I have a text file that contains a set of records and i am trying to convert and save it as 1's and 0's .. every time I use
Byte [] arr=Encoding.UTF8.GetBytes(recordss) ;
and write it using a byte writer i still have to same record file with no difference.
So my question is there a way to convert a string to binary and write it to a file in binary format. I am using c# by the way
Here is my code so far
public static void serialData()
{
FileStream recFile = new FileStream("Records.txt", FileMode.Open, FileAccess.ReadWrite); //file to be used for records
StreamReader recordRead = new StreamReader(recFile);
String recordss = recordRead.ReadToEnd(); //Reads Record file
recordRead.Close();
recFile.Close();
Byte [] arr=Encoding.UTF8.GetBytes(recordss) ;
FileStream file = new FileStream("Temp.txt", FileMode.Create, FileAccess.Write);
StreamWriter binfile = new StreamWriter(file);
for(int i =0; i < arr.Count();i++)
binfile.WriteLine(arr[i]);
binfile.Close();
file.Close();
}
There's a built-in function to convert from integer-type values to strings with binary representation. Try replacing the line
binfile.WriteLine(arr[i]);
by this line
binfile.WriteLine(
Convert.ToString(arr[i], 2)
);
Convert.ToString() will convert the input to a representation in the given base. In this case, you choose 2 as base for a binary representation. Other common values would be 8 for octal, or 16 for hexadecimal.
Your result is in 'byte' format. Always. By definition it is data. The way you 'see' it depends on the software you use to open it.
What you want is probably a file that when openned in a text editor 'shows' the underlying binary data of your original data source: as text. For this you'll have to write in the file as character '0' and '1'. Therefore, the final file will be a lot bigger thant the original data source.
Change this code:
for(int i =0; i < arr.Count();i++)
binfile.WriteLine(arr[i]);
Into this:
foreach (byte b in arr)
{
binfile.Write((b >> 7 & 1) == 0 ? '0' : '1');
binfile.Write((b >> 6 & 1) == 0 ? '0' : '1');
binfile.Write((b >> 5 & 1) == 0 ? '0' : '1');
binfile.Write((b >> 4 & 1) == 0 ? '0' : '1');
binfile.Write((b >> 3 & 1) == 0 ? '0' : '1');
binfile.Write((b >> 2 & 1) == 0 ? '0' : '1');
binfile.Write((b >> 1 & 1) == 0 ? '0' : '1');
binfile.Write((b & 1) == 0 ? '0' : '1');
}
But it is kind of ugly. Better use an hexadecimal file viewer.

Add one space after every two characters and add a character infront of every single character

I want to add one space after every two characters, and add a character in front of every single character.
This is my code:
string str2;
str2 = str1.ToCharArray().Aggregate("", (result, c) => result += ((!string.IsNullOrEmpty(result) && (result.Length + 1) % 3 == 0) ? " " : "") + c.ToString());
I have no problems separating every two characters with one space, but how do I know if the separated string has an individual character, and add a character infront of that character?
I understand that my question is confusing as I'm not sure how to put what I want in words..
So I'll just give an example:
I have this string:
0123457
After separating every two characters with a space, I'll get:
01 23 45 7
I want to add a 6 infront of the 7.
Note: Numbers are dependent on user's input, so it's not always the same.
Thanks.
[TestMethod]
public void StackOverflowQuestion()
{
var input = "0123457";
var temp = Regex.Replace(input, #"(.{2})", "$1 ");
Assert.AreEqual("01 23 45 7", temp);
}
Try something like this:
static string ProcessString(string input)
{
StringBuilder buffer = new StringBuilder(input.Length*3/2);
for (int i=0; i<input.Length; i++)
{
if ((i>0) & (i%2==0))
buffer.Append(" ");
buffer.Append(input[i]);
}
return buffer.ToString();
}
Naturally you'd need to add in some logic about the extra numbers, but the basic idea should be clear from the above.
May be you can try, if i right understand your request,
String.Length % 2
if result is 0, you done with first iteration, if not, just add a character infront of last one.
I think this is what you asked for
string str1 = "3322356";
string str2;
str2 = String.Join(" ",
str1.ToCharArray().Aggregate("",
(result, c) => result += ((!string.IsNullOrEmpty(result) &&
(result.Length + 1) % 3 == 0) ? " " : "") + c.ToString())
.Split(' ').ToList().Select(
x => x.Length == 1
? String.Format("{0}{1}", Int32.Parse(x) - 1, x)
: x).ToArray());
result is "33 22 35 56"

Categories

Resources