I've been trying to parse and search for a specific word in a big string, but I can't seem to be able to figure it out. I have created a script that connects a Twitch Channel's chat into unity.
An example of a message would be:
"#badge-info=subscriber/4;badges=moderator/1,subscriber/3,bits/1;bits=1;color=;display-name=TwitchUser1234;emotes=;flags=;id=da6ec4c6-af61-4346-abc-123456789;mod=1;room-id=12345678;subscriber=1;tmi-sent-ts=160987654321;turbo=0;user-id=123456789;user-type=mod :TwitchUser1234#TwitchUser1234.tmi.twitch.tv PRIVMSG #thechannelyouarewatching :PogChamp1 Another Test Bit"
I tried parsing and searching for the string 'bits' the message by doing:
private void GameInputs(string ChatInputs)
{
string Search;
Search = ChatInputs.Split(";", "=");
if(string "bits" in Search)
{
print("I made it here.");
}
}
I'm at a complete loss and have no idea how to do this. Any help is appreciated.
If my full code is needed it is:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;
using System.ComponentModel;
using System.Net.Sockets;
using System.IO;
public class TwitchChat : MonoBehaviour
{
private TcpClient twitchClient;
private StreamReader reader;
private StreamWriter writer;
public string username, password, channelName; // http://twitchapps.com/tmi
// Start is called before the first frame update
void Start()
{
Connect();
}
void Update()
{
if(!twitchClient.Connected)
{
Connect();
}
ReadChat();
}
private void Connect()
{
twitchClient = new TcpClient("irc.chat.twitch.tv", 6667);
reader = new StreamReader(twitchClient.GetStream());
writer = new StreamWriter(twitchClient.GetStream());
writer.WriteLine("PASS " + password);
writer.WriteLine("NICK " + username);
writer.WriteLine("USER " + username + " 8 * :" + username);
writer.WriteLine("JOIN #" + channelName);
writer.WriteLine("CAP REQ :twitch.tv/tags");
writer.Flush();
}
private void ReadChat()
{
if (twitchClient.Available > 0)
{
var message = reader.ReadLine();
print(message);
GameInputs(message);
}
}
private void GameInputs(string ChatInputs)
{
string Search;
Search = ChatInputs.Split(";", "=");
if(string "bits" in Search)
{
print("I made it here.");
}
}
}
If you want to pull the value of "bits=xx" out, this would do it:
var b = value.Split(';').FirstOrDefault(s => s.StartsWith("bits="))?[5..];
b will be null if "bits=" is not present
If you're going to parse a lot of values out of this string consider turning it into a dictionary:
var c = new []{'='};
var d = value.Split(';').ToDictionary(s => s.Split(c,2)[0], s => s.Split(c,2)[1]);
It's slightly inefficient to split twice, if it bothers you, you can sub string:
value.Split(';').ToDictionary(s => s[..s.IndexOf('=')], s => s[s.IndexOf('=')+1..]);
This gives a dictionary of string, so you can do like:
if(d.ContainsKey("bits")){
var bits = int.Parse(d["bits"]);
...
String has a method Contains(string) that does the job:
if (ChantInputs.Contains("bits")
{
print("I made it here.");
}
You can try below.
private void GameInputs(string ChatInputs)
{
string[] Search = ChatInputs.Split(new char[] { ';', '=' });
foreach(string s in Search)
{
if(s == "bits")
{
print("I made it here.");
}
}
}
Below is the working code.
using System;
namespace ConsoleApp3
{
class Program
{
static void Main(string[] args)
{
string str = "one;two;test;three;test+test";
string[] strs = str.Split(new char[] { ';', '+' });
foreach(string s in strs)
{
if(s == "test")
{
Console.WriteLine(s);
}
}
Console.ReadLine();
}
}
}
Related
First:I have to make a statistics from my csv( https://pastebin.com/jxNSzVYP ) by province. Somewhere you can find a province like this "HU-GD" then you have to see that like "HU" so first 2 letters. And i have to count how many SI/GA/etc province are there. After, i have to write out, when it is at least 3. (If the csv changes, i mean there will no more HU/SI/ etc, and there will a new one, the program have to count that.) [Check: Describe expected result]
Second: I have to make a new "newCNtunnels.csv" file. When there is a province like this "HU-GD" i have to separete them and write them with same datas, just the province is different. [Check: Describe expected result]
I am not a big programmer, so please do not over complicate this.
Sorry for my English. It is not my first language, but probably you have already noticed this.
Thanks for the help!
I am using windows 10 and visual studio. C# language
struct datas
{
public string name;
public int length;
public string date;
public string province;
}
datas[] tunnel = new datas[99];
int i = 0;
int howmanyrow= 0;
StreamReader sr = new StreamReader("CNtunnels.csv");
sr.ReadLine();
while (!sr.EndOfStream)
{
String[] onerow= sr.ReadLine().Split(';');
tunnel[i].name= onerow[0];
tunnel[i].length= Convert.ToInt32(onerow[1]);
tunnel[i].date= onerow[2];
tunnel[i].province= onerow[3];
i++;
howmanyrow++;
}
sr.Close();
Excepted results:
https://pastebin.com/EsQz16A0
See following solution :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
namespace ConsoleApplication1
{
class Program
{
const string INPUT_CSV_FILENAME = #"c:\temp\test.csv";
const string OUTPUT_CSV_FILENAME = #"c:\temp\test1.csv";
const string OUTPUT_STATISTICS_FILENAME = #"c:\temp\statistic.txt";
static void Main(string[] args)
{
Data data = new Data(INPUT_CSV_FILENAME);
data.WriteStatistics(OUTPUT_STATISTICS_FILENAME);
data.WriteCSV(OUTPUT_CSV_FILENAME);
}
}
class Data
{
public static List<Data> datas = new List<Data>();
public string name;
public int length;
public string date;
public string province;
public Data() { }
public Data(string filename)
{
StreamReader reader = new StreamReader(filename);
string line = "";
int rowCount = 0;
while ((line = reader.ReadLine()) != null)
{
line = line.Trim();
if (line.Length > 0)
{
string[] splitArray = line.Split(new char[] { ';' });
if (++rowCount > 1)
{
string[] splitProvidence = splitArray[3].Split(new char[] { '-' });
foreach (string providence in splitProvidence)
{
Data newRow = new Data();
Data.datas.Add(newRow);
newRow.name = splitArray[0];
newRow.length = int.Parse(splitArray[1]);
newRow.date = splitArray[2];
newRow.province = providence;
}
}
}
}
}
public void WriteStatistics(string filename)
{
StreamWriter writer = new StreamWriter(filename);
var groups = datas.GroupBy(x => x.province).OrderByDescending(x => x.Count()).ToList();
foreach (var group in groups)
{
writer.WriteLine("{0} - {1}", group.Key, group.Count());
}
writer.Flush();
writer.Close();
}
public void WriteCSV(string filename)
{
StreamWriter writer = new StreamWriter(filename);
string header = string.Join(";", new string[] { "name","length","date","province"});
writer.WriteLine(header);
foreach (Data data in datas)
{
writer.WriteLine(string.Join(";",new string[] {
data.name,
data.length.ToString(),
data.date,
data.province
}));
}
writer.Flush();
writer.Close();
}
}
}
I'm not so expert on C# but i tried to do my best ,
this is a small console application that should get 2 arg2 ( by passing args to the exe or by console input) i have 2 issue with it and i can't find any other solution
Merging the files is not in the correct order, if the files name has
letters included. ex.
(1.docx , 2.docx , 3.docx ) it work => result.docx(1,2,3)
(1test.docx , 2rice.docx , 3john.docx ) => result.docx(3,1,2)
Can't get WINWORD.exe to close after its the appliaction is
completed
PS: This exe is being called by PHP line CMD.EXE
i tried all possible commands to release com objects then close application ,
what is my mistake here? how to optimize the code correctly?
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Office.Interop.Word;
using System.Reflection;
using System.Runtime.InteropServices;
using System.IO;
namespace DocEngine
{
public class Parameter
{
public string Name;
public string Value;
// Note we need to give a default constructor when override it
public Parameter()
{
}
}
class Program
{
public static void MergeDocuments(string fileName, List<string> documentFiles)
{
_Application oWord = new Microsoft.Office.Interop.Word.Application();
_Document oDoc = oWord.Documents.Add();
Selection oSelection = oWord.Selection;
foreach (string documentFile in documentFiles)
{
_Document oCurrentDocument = oWord.Documents.Add(documentFile);
CopyPageSetup(oCurrentDocument.PageSetup, oDoc.Sections.Last.PageSetup);
oCurrentDocument.Range().Copy();
oSelection.PasteAndFormat(WdRecoveryType.wdFormatOriginalFormatting);
if (!Object.ReferenceEquals(documentFile, documentFiles.Last()))
oSelection.InsertBreak(WdBreakType.wdSectionBreakNextPage);
}
oDoc.SaveAs(fileName, WdSaveFormat.wdFormatDocumentDefault);
oDoc.Close();
//TODO: release objects, close word application
//Marshal.ReleaseComObject(oSelection);
//Marshal.ReleaseComObject(oDoc);
//Marshal.ReleaseComObject(oWord);
Marshal.FinalReleaseComObject(oSelection);
Marshal.FinalReleaseComObject(oDoc);
Marshal.FinalReleaseComObject(oWord);
System.Runtime.InteropServices.Marshal.FinalReleaseComObject(oWord);
System.Runtime.InteropServices.Marshal.ReleaseComObject(oSelection);
System.Runtime.InteropServices.Marshal.ReleaseComObject(oDoc);
System.Runtime.InteropServices.Marshal.ReleaseComObject(oWord);
oSelection = null;
oDoc = null;
oWord = null;
// A good idea depending on who you talk to...
GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();
GC.WaitForPendingFinalizers();
}
public static void CopyPageSetup(PageSetup source, PageSetup target)
{
target.PaperSize = source.PaperSize;
//target.Orientation = source.Orientation; //not working in word 2003, so here is another way
if (!source.Orientation.Equals(target.Orientation))
target.TogglePortrait();
target.TopMargin = source.TopMargin;
target.BottomMargin = source.BottomMargin;
target.RightMargin = source.RightMargin;
target.LeftMargin = source.LeftMargin;
target.FooterDistance = source.FooterDistance;
target.HeaderDistance = source.HeaderDistance;
target.LayoutMode = source.LayoutMode;
}
static void Main(string[] args)
{
if (args == null || args.Length == 0)
{
Console.WriteLine("Enter Path:");
Parameter parameter1 = new Parameter
{
Name = "dir",
Value = Console.ReadLine()
};
Console.WriteLine("FileName without ext:");
Parameter parameter2 = new Parameter
{
Name = "fileName",
Value = Console.ReadLine()
};
Console.WriteLine("Thank you! ");
Console.WriteLine("Test parameter1: [{0}] = [{1}]", parameter1.Name, parameter1.Value);
Console.WriteLine("Test parameter2: [{0}] = [{1}]", parameter2.Name, parameter2.Value);
try
{
List<string> result = Directory.EnumerateFiles(parameter1.Value, "*.doc", SearchOption.AllDirectories).Union(Directory.EnumerateFiles(parameter1.Value, "*.docx", SearchOption.AllDirectories)).ToList();
var filename = Path.Combine(parameter1.Value, parameter2.Value);
MergeDocuments(filename, result);
}
catch (UnauthorizedAccessException UAEx)
{
Console.WriteLine(UAEx.Message);
}
catch (PathTooLongException PathEx)
{
Console.WriteLine(PathEx.Message);
}
}
else
{
//args = new string[2];
string sourceDirectory = args[0];
string filename1 = args[1];
try
{
List<string> result = Directory.EnumerateFiles(sourceDirectory, "*.doc", SearchOption.AllDirectories).Union(Directory.EnumerateFiles(sourceDirectory, "*.docx", SearchOption.AllDirectories)).ToList();
var filename = Path.Combine(sourceDirectory, filename1);
MergeDocuments(filename, result);
}
catch (UnauthorizedAccessException UAEx)
{
Console.WriteLine(UAEx.Message);
}
catch (PathTooLongException PathEx)
{
Console.WriteLine(PathEx.Message);
}
}
}
}
}
You don't need to make any of those COM calls or explicit GC calls, and you don't need to explicitly set things to null. You just need to call Application.Quit.
If we had some string like :
----------DBVer=1
/*some sql script*/
----------DBVer=1
----------DBVer=2
/*some sql script*/
----------DBVer=2
----------DBVer=n
/*some sql script*/
----------DBVer=n
Can we extract scripts between first DBVer=1 and second DBVer=1 and so on... with regex?
I thing we must have some placehoder for regex, and tel regex engine if saw DBVer=digitA pick string until DBVer=digitA again if saw DBVer=digitB pick string until DBVer=digitB and so on...
Can we implement this with regex and if we can how?
Yes, using backreferences and lookarounds, you can capture the scripts:
var pattern = #"(?<=(?<m>-{10}DBVer=\d+)\r?\n).*(?=\r?\n\k<m>)";
var scripts = Regex.Matches(input, pattern, RegexOptions.Singleline)
.Cast<Match>()
.Select(m => m.Value);
Here, we capture the m (marker) group with (?<m>-{10}DBVer=\d+) and reuse the m value later in the regex with \k<m> to match against the end marker.
In order for .* to match newline chars, it is necessary to turn on Singleline mode. This, in turn, means we have to be specific about our newlines. In Singleline mode, these can be accounted for in a non-platform specific way with \r?\n.
Try code below. Not RegEx but works very well.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Text.RegularExpressions;
namespace ConsoleApplication6
{
class Program
{
const string FILENAME = #"c:\temp\test.txt";
static void Main(string[] args)
{
Script.ReadScripts(FILENAME);
}
}
public class Script
{
enum State
{
Get_Script,
Read_Script
}
public static List<Script> scripts = new List<Script>();
public int version { get; set; }
public string script { get; set; }
public static void ReadScripts(string filename)
{
string inputLine = "";
string pattern = "DBVer=(?'version'\\d+)";
State state = State.Get_Script;
StreamReader reader = new StreamReader(filename);
Script newScript = null;
while ((inputLine = reader.ReadLine()) != null)
{
inputLine = inputLine.Trim();
if (inputLine.Length > 0)
{
switch (state)
{
case State.Get_Script :
if(inputLine.StartsWith("-----"))
{
newScript = new Script();
scripts.Add(newScript);
string version =
Regex.Match(inputLine, pattern).Groups["version"].Value;
newScript.version = int.Parse(version);
newScript.script = "";
state = State.Read_Script;
}
break;
case State.Read_Script :
if (inputLine.StartsWith("-----"))
{
state = State.Get_Script;
}
else
{
if (newScript.script.Length == 0)
{
newScript.script = inputLine;
}
else
{
newScript.script += "\n" + inputLine;
}
}
break;
}
}
}
}
}
}
Just curious if there is a more simplified version to check if the given body has the word style of "Heading3" applied given this sample C# code I wrote learning the OpenXML library. To be clear, I am just asking given a body element how can I determine if the given body element has what word style applied. I eventually have to write a program that process numerous .DOCX files and need to process them from a top to bottom approach.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using DocumentFormat.OpenXml.Packaging;
using DocumentFormat.OpenXml.Wordprocessing;
using System.IO;
namespace docxparsing
{
class Program
{
static void Main()
{
string file_to_parse = #"C:\temp\sample.docx";
WordprocessingDocument doc = WordprocessingDocument.Open(file_to_parse,false);
Body body = doc.MainDocumentPart.Document.Body;
string fooStr
foreach( var foo in body )
{
fooStr = foo.InnerXml;
/*
these 2 comments represent 2 different xml snippets from 'fooStr'. the only way i figure out how to get the word style is by reading
this xml and doing checks for values. i don't know of any other approach in using the body element to check for the applied word style
<w:pPr xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main"><w:pStyle w:val="Heading2" />
<w:pPr xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main"><w:pStyle w:val="Heading3" />
*/
bool hasHeading3 = fooStr.Contains("pStyle w:val=\"Heading3\"");
if ( hasHeading3 )
{
Console.WriteLine("heading3 found");
}
}
doc.Close();
}
}
}
// -------------------------------------------------------------------------------
EDIT
Here is updated code of one way to do this. Still not overall happy with it but it works. Function to look at is getWordStyleValue(string x)
using DocumentFormat.OpenXml.Packaging;
using DocumentFormat.OpenXml.Wordprocessing;
using System;
using System.Diagnostics;
using System.IO;
using System.Text;
namespace docxparsing
{
class Program
{
// ************************************************
// grab the word style value
// ************************************************
static string getWordStyleValue(string x)
{
int p = 0;
p = x.IndexOf("w:pStyle w:val=");
if ( p == -1 )
{
return "";
}
p = p + 15;
StringBuilder sb = new StringBuilder();
while (true)
{
p++;
char c = x[p];
if (c != '"')
{
sb.Append(c);
}
else
{
break;
}
}
string s = sb.ToString();
return s;
}
// ************************************************
// Main
// ************************************************
static void Main(string[] args)
{
string theFile = #"C:\temp\sample.docx";
WordprocessingDocument doc = WordprocessingDocument.Open(theFile,false);
string body_table = "DocumentFormat.OpenXml.Wordprocessing.Table";
string body_paragraph = "DocumentFormat.OpenXml.Wordprocessing.Paragraph";
Body body = doc.MainDocumentPart.Document.Body;
StreamWriter sw1 = new StreamWriter("paragraphs.log");
foreach (var b in body)
{
string body_type = b.ToString();
if (body_type == body_paragraph)
{
string str = getWordStyleValue(b.InnerXml);
if (str == "" || str == "HeadingNon-TOC" || str == "TOC1" || str == "TOC2" || str == "TableofFigures" || str == "AcronymList" )
{
continue;
}
sw1.WriteLine(str + "," + b.InnerText);
}
if ( body_type == body_table )
{
// sw1.WriteLine("Table:\n{0}",b.InnerText);
}
}
doc.Close();
sw1.Close();
}
}
}
Yes. You could do something like this:
bool ContainsHeading3 = body.Descendants<ParagraphSytleId>().Any(psId => psId.Val == "Heading3");
This will look at all the ParagraphStyleId elements (w:pStyle in the xml) and see if any of them have the Val of Heading3.
Just pasting this Edit from original post so he has better visibility.
Here is one solution I came up with. Yes, it a little cody ( if that is a word ) but working LINQ ( my fav ) to optimize a more elegant solution.
--
Here is updated code of one way to do this. Still not overall happy with it but it works. Function to look at is getWordStyleValue(string x)
using DocumentFormat.OpenXml.Packaging;
using DocumentFormat.OpenXml.Wordprocessing;
using System;
using System.Diagnostics;
using System.IO;
using System.Text;
namespace docxparsing
{
class Program
{
// ************************************************
// grab the word style value
// ************************************************
static string getWordStyleValue(string x)
{
int p = 0;
p = x.IndexOf("w:pStyle w:val=");
if ( p == -1 )
{
return "";
}
p = p + 15;
StringBuilder sb = new StringBuilder();
while (true)
{
p++;
char c = x[p];
if (c != '"')
{
sb.Append(c);
}
else
{
break;
}
}
string s = sb.ToString();
return s;
}
// ************************************************
// Main
// ************************************************
static void Main(string[] args)
{
string theFile = #"C:\temp\sample.docx";
WordprocessingDocument doc = WordprocessingDocument.Open(theFile,false);
string body_table = "DocumentFormat.OpenXml.Wordprocessing.Table";
string body_paragraph = "DocumentFormat.OpenXml.Wordprocessing.Paragraph";
Body body = doc.MainDocumentPart.Document.Body;
StreamWriter sw1 = new StreamWriter("paragraphs.log");
foreach (var b in body)
{
string body_type = b.ToString();
if (body_type == body_paragraph)
{
string str = getWordStyleValue(b.InnerXml);
if (str == "" || str == "HeadingNon-TOC" || str == "TOC1" || str == "TOC2" || str == "TableofFigures" || str == "AcronymList" )
{
continue;
}
sw1.WriteLine(str + "," + b.InnerText);
}
if ( body_type == body_table )
{
// sw1.WriteLine("Table:\n{0}",b.InnerText);
}
}
doc.Close();
sw1.Close();
}
}
}
Description
Download multiple files using webclient's DownloadFileAsync and utilizing a text file for URL input for download.
Problem
The approach that I have used won't download files at all. Just runs and does nothing. It fills the list array then quits the program without downloading a single file. I have googled for solutions but come up shorthanded. Then attempted to search for a solution in the database here with same results. Any help is appreciated.
Questions
Why does this approach not work?
What can I do to improve this and learn from this.
Code
DownloadClass.cs
using System;
using System.ComponentModel;
using System.Collections.Generic;
using System.Net;
using System.Threading;
using System.Windows.Forms;
namespace ThreadTest
{
class DownloadClass
{
public struct download
{
public static string URL { get; set; }
public static string file { get; set; }
public static string[] link;
public static int downloadcount;
}
public static List<string> list = new List<string>();
public static WebClient wc = new WebClient();
public static void Download()
{
int count = 0;
download.URL = list[0];
Uri URI = new Uri(download.URL);
UriBuilder uri = new UriBuilder(URI);
download.link = uri.Path.ToLower().Split(new char[] { '/' });
count = 0;
// Find file
foreach (string abs in download.link)
{
count++;
if (abs.ToLower().Contains(".html") || abs.ToLower().Contains(".exe") || abs.ToLower().Contains(".txt"))
{
try
{
download.file = download.link[count];
wc.Proxy = null;
wc.DownloadFileCompleted += new AsyncCompletedEventHandler(wc_DownloadFileCompleted);
wc.DownloadFileAsync(URI, Application.StartupPath + "\\" + download.file);
break;
}
catch (Exception)
{ }
}
}
}
public static void BeginDownload()
{
new Thread(Download).Start();
}
public static void wc_DownloadFileCompleted(object sender, AsyncCompletedEventArgs e)
{
int count = 0;
download.downloadcount++;
download.URL = list[0];
Uri URI = new Uri(download.URL);
UriBuilder uri = new UriBuilder(URI);
download.link = uri.Path.ToLower().Split(new char[] { '/' });
count = 0;
// Find file
foreach (string abs in download.link)
{
count++;
if (abs.ToLower().Contains(".html") || abs.ToLower().Contains(".exe") || abs.ToLower().Contains(".txt"))
{
try
{
download.file = download.link[count];
}
catch (Exception)
{ }
}
}
list.RemoveAt(0);
if (list.Count > 0)
{
wc.DownloadFileAsync(URI, list[download.downloadcount], Application.StartupPath + "\\" + download.file);
}
else
{
Console.WriteLine("Downloading is done.");
Environment.Exit(0);
}
}
}
}
Program.cs (Main Class)
using System;
using System.IO;
using System.Collections.Generic;
using System.Windows.Forms;
namespace ThreadTest
{
class Program
{
static void Main(string[] args)
{
if (args.Length < 1)
{
Console.WriteLine("Usage: {0} <download txtfile>", Environment.GetCommandLineArgs()[0]);
Environment.Exit(0);
}
int counter = 0;
string line;
string format = string.Format("{0}\\{1}", Application.StartupPath, args[0]);
// Read the file line by line.
using(StreamReader file = new StreamReader(format))
{
while ((line = file.ReadLine())!= null)
{
// Store urls in a list.
DownloadClass.list.Add(line);
counter++;
}
}
DownloadClass.BeginDownload();
}
}
}
Besides being bad design there are lots of issues that lead to your code not (or nor correctly working).
You need to make sure that you application lives while it downloads something. Your current app quits right away (you have to wait for the downloading to complete in your main).
You application may download the same file multiple times but not download others at all (You need to completely lock object when they are used in an async=multithreading way like here when accessing static objects) BTW: Don't use static objects at all to avoid that in the first place.
Even if 2 is corrected it may still download the same file multiple times into the same filename and thus fail.
As long as you have no knowledge about multithreading I'd recommend you use the synchoneous methods to avoid all those problems.