How can I convert a string to DateTime in Unity? - c#

I'm currently working on a virtual pet game, and I need help to solve this issue, as fast as possible.
I'm trying to get the timeSpan of between now and the last time I've played, and the script doesn't continue after the part of the timeSpan (Mentioned below the script, including the main question).
The Script:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Bird : MonoBehaviour {
[SerializeField]
private int _hunger;
[SerializeField]
private int _happiness;
[SerializeField]
private string _name;
private bool _servertime;
private int _clickCount;
DateTime timeSpan4;
void Start()
{
print("Then: " + PlayerPrefs.GetString("then"));
print("getStringTime(): " + getStringTime());
print("TimeOfDay: " + DateTime.Now.TimeOfDay);
print("DateTime now: " + DateTime.Now);
//PlayerPrefs.SetString("then", "09 / 12 / 2019 20:50:0");
updateStatus();
//if (!PlayerPrefs.HasKey("name"))
// PlayerPrefs.SetString("name", "Bird");
_name = PlayerPrefs.GetString("name");
}
void Update()
{
GetComponent<Animator>().SetBool("Fly", gameObject.transform.position.y > -2.3);
if (Input.GetMouseButtonUp(0))
{
//Debug.Log("Clicked");
Vector2 v = new Vector2(Input.mousePosition.x, Input.mousePosition.y);
RaycastHit2D hit = Physics2D.Raycast(Camera.main.ScreenToWorldPoint(v), Vector2.zero);
if (hit)
{
//Debug.Log(hit.transform.gameObject.name);
if(hit.transform.gameObject.tag == "Birb")
{
_clickCount++;
if(_clickCount >= 3)
{
_clickCount = 0;
updateHappiness(5);
GetComponent<Rigidbody2D>().AddForce(new Vector2(0, 1000));
}
}
}
}
}
public void updateStatus()
{
print("Updating Status...");
if (!PlayerPrefs.HasKey("_hunger"))
{
_hunger = 100;
PlayerPrefs.SetInt("_hunger", _hunger);
}
else
{
_hunger = PlayerPrefs.GetInt("_hunger");
}
if (!PlayerPrefs.HasKey("_happiness"))
{
_happiness = 100;
PlayerPrefs.SetInt("_happiness", _happiness);
}
else
{
_happiness = PlayerPrefs.GetInt("_happiness");
}
if (!PlayerPrefs.HasKey("then"))
PlayerPrefs.SetString("then", getStringTime());
TimeSpan ts = getTimeSpan();
_hunger -= (int)(ts.TotalHours * 2);
if (_hunger < 0)
{
_hunger = 0;
PlayerPrefs.SetInt("_hunger", _hunger);
}
if (_hunger > 100)
{
_hunger = 100;
PlayerPrefs.SetInt("_hunger", _hunger);
print("hunger is bigger than 100!");
}
_happiness -= (int)((100 - _hunger) * (ts.TotalHours / 5));
if (_happiness < 0)
{
_happiness = 0;
PlayerPrefs.SetInt("_happiness", _happiness);
}
if (_happiness > 100)
{
_happiness = 0;
PlayerPrefs.SetInt("_happiness", _happiness);
}
//Debug.Log(getTimeSpan().ToString());
//Debug.Log(getTimeSpan().TotalHours);
if (_servertime)
updateServer();
else
InvokeRepeating("saveBird", 0f, 2f);
}
void updateServer()
{
}
void updateDevice()
{
PlayerPrefs.SetString("then", getStringTime());
}
TimeSpan getTimeSpan()
{
if (_servertime)
return new TimeSpan();
else
return DateTime.Now - Convert.ToDateTime(PlayerPrefs.GetString("then"));
}
string getStringTime()
{
DateTime now = DateTime.Now;
return now.Day + "-" + now.Month + "-" + now.Year + " " + now.Hour + ":" + now.Minute + ":" + now.Second;
}
public int hunger
{
get { return _hunger; }
set { _hunger = value; }
}
public int happiness
{
get { return _happiness; }
set { _happiness = value; }
}
public string BName
{
get { return _name; }
set { _name = value; }
}
public void updateHappiness(int i)
{
happiness += i;
if (happiness > 100)
happiness = 100;
}
public void saveBird()
{
if (!_servertime)
updateDevice();
PlayerPrefs.SetInt("_hunger", _hunger);
PlayerPrefs.SetInt("_happiness", _happiness);
}
}
The problem is in line 134 (return DateTime.Now - Convert.ToDateTime(PlayerPrefs.GetString("then"));), it prints FormatException: String was not recognized as a valid DateTime., and because of that the script doesn't continue after that part. How can I convert the string "then" to a DateTime so it won't error?

The exact format for loading a date from a string depends on a lot of factors. One of the most important being the locale.
That being said you're a lot safer if you use DateTimes string formatting methods instead of saving it by hand.
You can change your getStringTime() to rely on ToString and save that:
string getStringTime() {
return DateTime.Now.ToString();
}

Related

Strange unity bug in IOS

I am suffering from a strange bug in my project. It runs in unity perfectly but when I build it for IOS, it does one thing in particular differently. When a user picks up 8 items, I have an input box display these items and what order they selected them in. This works perfectly in unity but doesn't in IOS. Anyone have any suggestions as to why this might be the case. Below are the two appropriate scripts.
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using System.IO;
public class PickUpItem : MonoBehaviour, IInteractable
{
//Go back to older version of clavem, find out what broke.
public string DisplaySprite;
public string DisplayImage;
public static string ItemChoosenOrder;
public static int counter;
public static GameObject InventorySlots;
public static GameObject[] PlayerItems = new GameObject[8];
public void Interact(DisplayImage currentDisplay)
{
ItemPickUp();
}
void Start()
{
PlayerItems = GameObject.FindGameObjectsWithTag("ChoosenItem");
}
void Update()
{
}
public void ItemPickUp()
{
InventorySlots = GameObject.Find("Slots");
counter = 0;
foreach (Transform slot in InventorySlots.transform)
{
if (slot.transform.GetChild(0).GetComponent<Image>().sprite.name == "empty_item")
{
slot.transform.GetChild(0).GetComponent<Image>().sprite =
Resources.Load<Sprite>("Inventory Items/" + DisplaySprite);
Destroy(gameObject);
break;
}
if (counter <= 7)
{
counter++;
if (counter >= 7)
{
{
Debug.Log("You have choosen all your items.");
foreach (Transform finalslot in InventorySlots.transform)
{
if (finalslot.transform.GetChild(0).GetComponent<Image>().sprite.name == "empty_item")
{
finalslot.transform.GetChild(0).GetComponent<Image>().sprite =
Resources.Load<Sprite>("Inventory Items/" + DisplaySprite);
Destroy(gameObject);
break;
}
}
//https://hub.packtpub.com/arrays-lists-dictionaries-unity-3d-game-development/
if (PlayerItems[7].GetComponent<Image>().sprite.name != "empty_item")
{
PlayerItems = GameObject.FindGameObjectsWithTag("ChoosenItem");
ItemChoosenOrder = "1: " + PlayerItems[0].GetComponent<Image>().sprite.name + " 2: " + PlayerItems[1].GetComponent<Image>().sprite.name
+ " 3: " + PlayerItems[2].GetComponent<Image>().sprite.name + " 4: " + PlayerItems[3].GetComponent<Image>().sprite.name
+ " 5: " + PlayerItems[4].GetComponent<Image>().sprite.name + " 6: " + PlayerItems[5].GetComponent<Image>().sprite.name
+ " 7: " + PlayerItems[6].GetComponent<Image>().sprite.name + " 8: " + PlayerItems[7].GetComponent<Image>().sprite.name;
Debug.Log(ItemChoosenOrder);
Debug.Log(counter);
}
else
{
Debug.Log("Error choosing items");
}
}
}
}
}
}
}
saveitemhash
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class SaveItemHash : MonoBehaviour
{
public InputField choosenitems;
public Text playerDisplay;
public Text InfoText;
public Button SaveButton;
private void Awake()
{
if (DBManager.email == null)
{
UnityEngine.SceneManagement.SceneManager.LoadScene(0);
}
playerDisplay.text = "User: " + DBManager.email;
}
public void CallAddItems()
{
StartCoroutine(AddChoosenItems());
}
IEnumerator AddChoosenItems()
{
//Using a unity web request to send email and choosen items string to my php scripts which echo a number depending on whether the user is successful or not.
WWWForm form = new WWWForm();
form.AddField("email", DBManager.email);
form.AddField("items", choosenitems.text);
WWW www = new WWW("https://clavem.000webhostapp.com/userregister.php", form);
yield return www;
if (www.text[0] == '0')
{
Debug.Log("User added successfully.");
UnityEngine.SceneManagement.SceneManager.LoadScene(0);
PickUpItem.counter = 0;
PickUpItem.ItemChoosenOrder = " ";
}
else
{
Debug.Log("User adding failed. Error #" + www.text);
InfoText.text = www.text;
PickUpItem.counter = 0;
PickUpItem.ItemChoosenOrder = " ";
}
}
public void Update()
{
playerDisplay.text = "User: " + DBManager.email;
if (PickUpItem.counter > 7)
{
//Do this for add field in last scene where the passwords are.
GameObject.Find("SaveButton").transform.localScale = new Vector3(1, 1, 1);
choosenitems.text = PickUpItem.ItemChoosenOrder;
GameObject.Find("InputField").transform.localScale = new Vector3(1, 1, 1);
//choosenitems.text = PickUpItem.ItemChoosenOrder;
//Debug.Log(PickUpItem.ItemChoosenOrder);
}
if (PickUpItem.counter < 7)
{
GameObject.Find("SaveButton").transform.localScale = new Vector3(0, 0, 0);
GameObject.Find("InputField").transform.localScale = new Vector3(0, 0, 0);
}
}
public void RestartScene()
{
UnityEngine.SceneManagement.SceneManager.LoadScene(3); ;
PickUpItem.counter = 0;
PickUpItem.ItemChoosenOrder = " ";
}
}
Working answer using a List collection and directly linking the order by adding each item to the array corresponding to each inventory slot in the appropriate order.
PickUpItem Script
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using System.IO;
using System.Linq;
public class PickUpItem : MonoBehaviour, IInteractable
{
public string DisplaySprite;
public string DisplayImage;
public static List<string> itemOrder = new List<string>();
public static string ItemChoosenOrder;
public static int counter;
public static GameObject InventorySlots;
public static GameObject[] PlayerItems = new GameObject[8];
public void Interact(DisplayImage currentDisplay)
{
ItemPickUp();
}
void Start()
{
PlayerItems = GameObject.FindGameObjectsWithTag("ChoosenItem");
}
void Update()
{
}
public void ItemPickUp()
{
InventorySlots = GameObject.Find("Slots");
counter = 0;
int j;
foreach (Transform slot in InventorySlots.transform)
{
if (slot.transform.GetChild(0).GetComponent<Image>().sprite.name == "empty_item")
{
slot.transform.GetChild(0).GetComponent<Image>().sprite =
Resources.Load<Sprite>("Inventory Items/" + DisplaySprite);
Destroy(gameObject);
break;
}
if (counter <= 7)
{
//itemOrder.Add(PlayerItems[counter].GetComponent<Image>().sprite.name);
counter++;
if (counter >= 7)
{
{
PlayerItems = GameObject.FindGameObjectsWithTag("ChoosenItem");
Debug.Log("You have choosen all your items.");
foreach (Transform finalslot in InventorySlots.transform)
{
if (finalslot.transform.GetChild(0).GetComponent<Image>().sprite.name == "empty_item")
{
finalslot.transform.GetChild(0).GetComponent<Image>().sprite =
Resources.Load<Sprite>("Inventory Items/" + DisplaySprite);
Destroy(gameObject);
break;
}
}
itemOrder.Add(GameObject.Find("item0").GetComponent<Image>().sprite.name);
itemOrder.Add(GameObject.Find("item1").GetComponent<Image>().sprite.name);
itemOrder.Add(GameObject.Find("item2").GetComponent<Image>().sprite.name);
itemOrder.Add(GameObject.Find("item3").GetComponent<Image>().sprite.name);
itemOrder.Add(GameObject.Find("item4").GetComponent<Image>().sprite.name);
itemOrder.Add(GameObject.Find("item5").GetComponent<Image>().sprite.name);
itemOrder.Add(GameObject.Find("item6").GetComponent<Image>().sprite.name);
itemOrder.Add(GameObject.Find("item7").GetComponent<Image>().sprite.name);
//https://hub.packtpub.com/arrays-lists-dictionaries-unity-3d-game-development/
if (PlayerItems[7].GetComponent<Image>().sprite.name != "empty_item")
{
PlayerItems = GameObject.FindGameObjectsWithTag("ChoosenItem");
for (j = 0; j < 8; j++)
{
Debug.LogFormat("Item[{0}] = {1}", j, itemOrder[j]);
}
ItemChoosenOrder = "1: " + itemOrder[0] + " 2: " + itemOrder[1]
+ " 3: " + itemOrder[2] + " 4: " + itemOrder[3]
+ " 5: " + itemOrder[4] + " 6: " + itemOrder[5]
+ " 7: " + itemOrder[6] + " 8: " + itemOrder[7];
Debug.Log(ItemChoosenOrder);
}
else
{
Debug.Log("Error choosing items");
}
}
}
}
}
}
}

How can I calculate and display the download speed per file?

private void DownloadFile() {
if (_downloadUrls.Any()) {
WebClient client = new WebClient();
client.DownloadProgressChanged += client_DownloadProgressChanged;
client.DownloadFileCompleted += client_DownloadFileCompleted;
var url = _downloadUrls.Dequeue();
string startTag = "animated/";
string endTag = "/infra";
int index = url.IndexOf(startTag);
int index1 = url.IndexOf(endTag);
string fname = url.Substring(index + 9, index1 - index - 9);
client.DownloadFileAsync(new Uri(url), #"C:\Temp\tempframes\" + fname + ".gif");
lastDownloadedFile = #"C:\Temp\tempframes\" + fname + ".gif";
label1.Text = url;
return;
}
// End of the download
btnStart.Text = "Download Complete";
}
private void client_DownloadFileCompleted(object sender, AsyncCompletedEventArgs e) {
if (e.Error != null) {
// handle error scenario
throw e.Error;
}
if (e.Cancelled) {
// handle cancelled scenario
}
Image img = new Bitmap(lastDownloadedFile);
Image[] frames = GetFramesFromAnimatedGIF(img);
foreach(Image image in frames) {
countFrames++;
image.Save(#"C:\Temp\tempframes\" + countFrames + ".gif");
}
DownloadFile();
}
void client_DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e) {
double bytesIn = double.Parse(e.BytesReceived.ToString());
double totalBytes = double.Parse(e.TotalBytesToReceive.ToString());
double percentage = bytesIn / totalBytes * 100;
pBarFileProgress.Value = int.Parse(Math.Truncate(percentage).ToString());
label1.Text = e.BytesReceived.ToString() + "/" + e.TotalBytesToReceive.ToString();
}
Now I added this method
DateTime lastUpdate;
long lastBytes = 0;
private void progressChanged(long bytes) {
if (lastBytes == 0) {
lastUpdate = DateTime.Now;
lastBytes = bytes;
return;
}
var now = DateTime.Now;
var timeSpan = now - lastUpdate;
var bytesChange = bytes - lastBytes;
var bytesPerSecond = bytesChange / timeSpan.Seconds;
lastBytes = bytes;
lastUpdate = now;
}
And I want to use this method or another method to display the download speed in the progresschanged event on label2. But I'm not sure how to use this method.
Not sure how to use with it in the progresschanged event.
The call to your prepared method progressChanged would best fit into client_DownloadProgressChanged like this:
progressChanged(e.BytesReceived);
You must however use TotalSeconds instead of Seconds or the values will not be correct and also cause a division by zero exception
var bytesPerSecond = bytesChange / timeSpan.TotalSeconds;
This helper class will keep track of received chunks, timestamps and progress for you:
public class DownloadProgressTracker
{
private long _totalFileSize;
private readonly int _sampleSize;
private readonly TimeSpan _valueDelay;
private DateTime _lastUpdateCalculated;
private long _previousProgress;
private double _cachedSpeed;
private Queue<Tuple<DateTime, long>> _changes = new Queue<Tuple<DateTime, long>>();
public DownloadProgressTracker(int sampleSize, TimeSpan valueDelay)
{
_lastUpdateCalculated = DateTime.Now;
_sampleSize = sampleSize;
_valueDelay = valueDelay;
}
public void NewFile()
{
_previousProgress = 0;
}
public void SetProgress(long bytesReceived, long totalBytesToReceive)
{
_totalFileSize = totalBytesToReceive;
long diff = bytesReceived - _previousProgress;
if (diff <= 0)
return;
_previousProgress = bytesReceived;
_changes.Enqueue(new Tuple<DateTime, long>(DateTime.Now, diff));
while (_changes.Count > _sampleSize)
_changes.Dequeue();
}
public double GetProgress()
{
return _previousProgress / (double) _totalFileSize;
}
public string GetProgressString()
{
return String.Format("{0:P0}", GetProgress());
}
public string GetBytesPerSecondString()
{
double speed = GetBytesPerSecond();
var prefix = new[] { "", "K", "M", "G"};
int index = 0;
while (speed > 1024 && index < prefix.Length - 1)
{
speed /= 1024;
index++;
}
int intLen = ((int) speed).ToString().Length;
int decimals = 3 - intLen;
if (decimals < 0)
decimals = 0;
string format = String.Format("{{0:F{0}}}", decimals) + "{1}B/s";
return String.Format(format, speed, prefix[index]);
}
public double GetBytesPerSecond()
{
if (DateTime.Now >= _lastUpdateCalculated + _valueDelay)
{
_lastUpdateCalculated = DateTime.Now;
_cachedSpeed = GetRateInternal();
}
return _cachedSpeed;
}
private double GetRateInternal()
{
if (_changes.Count == 0)
return 0;
TimeSpan timespan = _changes.Last().Item1 - _changes.First().Item1;
long bytes = _changes.Sum(t => t.Item2);
double rate = bytes / timespan.TotalSeconds;
if (double.IsInfinity(rate) || double.IsNaN(rate))
return 0;
return rate;
}
}
In the following example, the progress tracker will give you the average download rate of the last 50 received Packets but only every 500 ms (so the UI doesn't flicker). You might need to tinker with the values a bit to find a good balance between accuracy and smoothness.
//Somewhere in your constructor / initializer:
tracker = new DownloadProgressTracker(50, TimeSpan.FromMilliseconds(500));
void client_DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e)
{
tracker.SetProgress(e.BytesReceived, e.TotalBytesToReceive);
pBarFileProgress.Value = tracker.GetProgress() * 100;
label1.Text = e.BytesReceived + "/" + e.TotalBytesToReceive;
label2.Text = tracker.GetBytesPerSecondString();
}
Keep in mind, that you have to reset the tracker before or after every new file:
tracker.NewFile();
In case you need some bigger files to test this with, I've found some here

Timer inside a listbox c#

So I am currently working on a program in which I need to have a timer attached to each item inside of a list box, I have that working, but I can't select any of the items, is there a way to be able to select the items but also have a timer displayed to each item in the list box?
Update:
when adding the item to a new list box here is the code that I have:
private void btnSchedule_Click(object sender, EventArgs e)
{
try
{
string name = lsbScheduled.SelectedItem.ToString();// saves the selected item to a string
string newItem = (moveItem(name));//calls the method and passes the variable to it
tmrCheckedIn.Enabled = true;
tmrCheckedIn.Start();
newItem += " " + "00:00:00";
lsbScheduled.Items.Remove(name);// removes the item from the list
lsbCheckedIn.Items.Add(newItem); //adds the item to the list
}
catch (NullReferenceException)
{
}
}
here is my code for the tick event:
private void tmrCheckedIn_Tick(object sender, EventArgs e)
{
int count = lsbCheckedIn.Items.Count;
for (int i = 0; i < count; i++)
{
string item = lsbCheckedIn.Items[i].ToString();
string[] line = item.Split();
string time = line[8];
Time oldTime = new Time();
oldTime.StartTime = time;
lsbCheckedIn.Items.Remove(item);
string newTime = string.Format(line[0] + " " + line[1] + " " +line[2] + " " + "{0:c}", oldTime.EndTime);
lsbCheckedIn.Items.Add(newTime);
oldTime = null;
}
}
and here is my class that I use to increase the timer:
public class Time
{
private int seconds, minutes, hours;
string startTime, endTime;
public Time()
{
seconds = 00;
minutes = 00;
hours = 00;
startTime = " ";
endTime = "";
}
public string StartTime
{
set { startTime = value;
CalcNewTime();
}
get { return startTime; }
}
public string EndTime
{
set { endTime = value; }
get { return endTime; }
}
public int Hours
{
set { hours = value; }
get { return hours; }
}
public int Minutes
{
set { minutes = value; }
get { return minutes; }
}
public int Second
{
set { seconds = value; }
get { return seconds; }
}
private void CalcNewTime()
{
const int LIMIT = 6, CONVERT = 10;
string[] divisions = startTime.Split(':');
hours = Convert.ToInt32(divisions[0]);
minutes = Convert.ToInt32(divisions[1]);
seconds = Convert.ToInt32(divisions[2]);
int hoursTens = hours / CONVERT;
int hoursOnes = hours % CONVERT;
int minutesTens = minutes / CONVERT;
int minuteOnes = minutes % CONVERT;
seconds += 1;
int secondTens = seconds / CONVERT;
int secondOnes = seconds % CONVERT;
if (secondTens >= LIMIT)
{
secondTens = 0;
secondOnes = 0;
minutes += 1;
minutesTens = Minutes / CONVERT;
minuteOnes = minutes % CONVERT;
if (minutesTens >= LIMIT)
{
minutesTens = 0;
minuteOnes = 0;
hours += 1;
hoursTens = hours / CONVERT;
hoursOnes = Hours % CONVERT;
}
}
endTime = Convert.ToString(hoursTens + hoursOnes + ":" + minutesTens + minuteOnes + ":" + secondTens + secondOnes);
}
}
in programming a windows form application using visual studio 2010 im using the timer that you can select from the toolbox. I need to be able to select the items in the list box but right now i can because im constantly adding and removing items from the list box. I want the time that is displayed in the list box to go up, but i also need it so that i can select the item in the list box.
Your problem is that you're removing items from the listbox, and then adding new ones. This is why items do not remain selected. Instead, just replace the items.
lsbCheckedIn.Items[i] = newTime;

c# text difference

I have two words:
Source: John
ConvertTo: Jack
and I want to show the effect of convert all letters from "Source" at the same time to the "ConvertTo" word. I already create a program to accomplish that but processing one letter at a time, to show the effect I use Threads, the thing is that to process all letters at the same time I suppose I need one thread per letter, and every thread will call the same function that process the letter, and I use global variables.
Here is the code (works only for texts with same lenght):
private void button1_Click(object sender, EventArgs e)
{
lblResult.Text = "";
lblResult2.Text = "";
ThreadPool.QueueUserWorkItem(new WaitCallback(Process));
}
int movement = 0;
string CumulateText;
private void Process(object stateinfo)
{
int value;
int operation; //0->[+] 1->[-]
CumulateText = "";
for (int i = 0; i <= textBox1.Text.Length - 1; i++)
{
if (textBox1.Text[i] != ' ')
{
value = (char)textBox1.Text[i] - (char)textBox2.Text[i];
if (value >= 0)
operation = 1;
else
operation = 0;
for (int ii = 0; ii <= Math.Abs(value); ii++)
{
if (operation == 1)
movement = (char)textBox1.Text[i] - ii;
else
movement = (char)textBox1.Text[i] + ii;
this.Invoke(new EventHandler(ShowMovement));
System.Threading.Thread.Sleep(10);
}
}
CumulateText += textBox2.Text[i].ToString();
}
}
private void ShowMovement(object sender, EventArgs e)
{
lblResult.Text = CumulateText + Convert.ToString((char)movement);
}
I hope I made myself understood.
please any advise to accomplish that.
thanks
To clarify more what I want to accomplish here is an example:
Source: John
ConvertTo: Jack
J - same J
o - decrease till a (o, n, m, ..., a)
h - decrease till c (h, g, f, ..., c)
n - decrease till k (n, m, l, k)
I once had to do something similar for a small little project I was working on for fun.
I do not see why you would need to create a thread for each letter to create a transition between two words unless I'm not understanding what you are pretending to do correctly.
Check and study the following code, see if its any help:
static class Program
{
static void Main()
{
TextTranstition transition = new TextTranstition();
transition.TransitionFinished += TransitionTicked;
transition.TransitionTicked += TransitionTicked;
transition.StartTransition("AmazingWordTransition", "MyNewWordAppearing", 100);
Thread.CurrentThread.Join();
Console.ReadKey();
}
public static void TransitionTicked(object sender, TranstitionEventArgs e)
{
Console.Clear();
Console.Write(e.TransitionText);
}
}
public class TranstitionEventArgs : EventArgs
{
private readonly string transitionText;
public string TransitionText { get { return this.transitionText; } }
public TranstitionEventArgs(string transitionText)
{
this.transitionText = transitionText;
}
}
public class TextTranstition
{
private struct StartInfo
{
public StartInfo(string initialText, string finalText, int timeStep)
{
this.initialText = initialText;
this.finalText = finalText;
this.timeStep = timeStep;
}
private readonly string initialText;
public string InitialText { get { return this.initialText; } }
private readonly string finalText;
public string FinalText { get { return this.finalText; } }
private readonly int timeStep;
public int TimeStep { get { return this.timeStep; } }
}
public EventHandler<TranstitionEventArgs> TransitionFinished;
public EventHandler<TranstitionEventArgs> TransitionTicked;
public void StartTransition(string initialText, string finalText, int timeStep)
{
StartInfo startInfo = new StartInfo(initialText, finalText, timeStep);
Thread t = new Thread(startTransition);
t.Start(startInfo);
}
private void startTransition(object info)
{
StartInfo startInfo = (StartInfo)info;
string initialText = startInfo.InitialText;
string finalText = startInfo.FinalText;
if (initialText.Length < finalText.Length)
{
initialText = initialText.PadRight(finalText.Length);
}
if (TransitionTicked != null) TransitionTicked(this, new TranstitionEventArgs(initialText));
while ((initialText = transition(initialText, finalText)) != finalText)
{
Thread.Sleep(startInfo.TimeStep);
if (TransitionTicked != null) TransitionTicked(this, new TranstitionEventArgs(initialText));
}
if (TransitionFinished != null) TransitionFinished(this, new TranstitionEventArgs(finalText));
}
private string transition(string initialText, string finalText)
{
StringBuilder b = new StringBuilder(finalText.Length);
for (int i = 0; i < finalText.Length; i++)
{
char c = initialText[i];
int charCode = (int)c;
if (c != finalText[i])
{
if (charCode == 122 || charCode==32) charCode = 65;
else if (charCode == 90) charCode = 97;
else
{
charCode += 1;
}
}
b.Append((char)charCode);
}
return b.ToString();
}
}
Use BackgroudWorker for this kind of stuff.

C# function to convert text input of feet/inches/meters/centimeters/millimeters into numeric values

I'm writing a function to take shorthand values and convert them into a standardized numeric format. Is there any standard code out there that would do "best possible" conversion of arbitrary measurement text and turn it into numeric measurements if the text is valid?
I guess I'm looking for something like bool TryParseMeasurement(string s, out decimal d). Does anyone know of a function like this?
Here's an example of some of the input values I've seen:
Imperial
6 inches
6in
6”
4 feet 2 inches
4’2”
4 ‘ 2 “
3 feet
3’
3 ‘
3ft
3ft10in
3ft 13in (should convert to 4’1”)
Metricc
1m
1.2m
1.321m
1 meter
481mm
Here's some code we wrote in an app quite some time ago, where we were doing something similar. It's not the best, but you may be able to adapt, or get some sort of jumping off point.
public static class UnitConversion
{
public static string[] lstFootUnits = new string[] {"foots", "foot", "feets", "feet", "ft", "f", "\""};
public static string sFootUnit = "ft";
public static string[] lstInchUnits = new string[] { "inches", "inchs", "inch", "in", "i", "\'" };
public static string sInchUnit = "in";
public static string[] lstPoundUnits = new string[] { "pounds", "pound", "pnds", "pnd", "lbs", "lb", "l", "p" };
public static string sPoundUnit = "lbs";
public static string[] lstOunceUnits = new string[] { "ounces", "ounce", "ozs", "oz", "o" };
public static string sOunceUnit = "oz";
public static string[] lstCentimeterUnits = new string[] { "centimeters", "centimeter", "centimetres", "centimetre", "cms", "cm", "c"};
public static string sCentimeterUnit = "cm";
public static string[] lstKilogramUnits = new string[] { "kilograms", "kilogram", "kilos", "kilo", "kgs", "kg", "k" };
public static string sKilogramsUnit = "kgs";
/// <summary>
/// Attempt to convert between feet/inches and cm
/// </summary>
/// <param name="sHeight"></param>
/// <returns></returns>
public static string ConvertHeight(string sHeight)
{
if (!String.IsNullOrEmpty(sHeight))
{
sHeight = UnitConversion.CleanHeight(sHeight);
if (sHeight.Contains(UnitConversion.sFootUnit))
{
sHeight = sHeight.Replace(UnitConversion.sFootUnit, "|");
sHeight = sHeight.Replace(UnitConversion.sInchUnit, "|");
string[] sParts = sHeight.Split('|');
double? dFeet = null;
double? dInches = null;
double dFeetParsed;
double dInchesParsed;
if (sParts.Length >= 2 && double.TryParse(sParts[0].Trim(), out dFeetParsed))
{
dFeet = dFeetParsed;
}
if (sParts.Length >= 4 && double.TryParse(sParts[2].Trim(), out dInchesParsed))
{
dInches = dInchesParsed;
};
sHeight = UnitConversion.FtToCm(UnitConversion.CalculateFt(dFeet ?? 0, dInches ?? 0)).ToString() + " " + UnitConversion.sCentimeterUnit;
}
else if (sHeight.Contains(UnitConversion.sCentimeterUnit))
{
sHeight = sHeight.Replace(UnitConversion.sCentimeterUnit, "|");
string[] sParts = sHeight.Split('|');
double? dCentimeters = null;
double dCentimetersParsed;
if (sParts.Length >= 2 && double.TryParse(sParts[0].Trim(), out dCentimetersParsed))
{
dCentimeters = dCentimetersParsed;
}
int? iFeet;
int? iInches;
if (UnitConversion.CmToFt(dCentimeters, out iFeet, out iInches))
{
sHeight = (iFeet != null) ? iFeet.ToString() + " " + UnitConversion.sFootUnit : "";
sHeight += (iInches != null) ? " " + iInches.ToString() + " " + UnitConversion.sInchUnit : "";
sHeight = sHeight.Trim();
}
else
{
sHeight = "";
}
}
else
{
sHeight = "";
}
}
else
{
sHeight = "";
}
return sHeight;
}
/// <summary>
/// Attempt to convert between Kgs and Lbs
/// </summary>
/// <param name="sWeight"></param>
/// <returns></returns>
public static string ConvertWeight(string sWeight)
{
if (!String.IsNullOrEmpty(sWeight))
{
sWeight = UnitConversion.CleanWeight(sWeight);
if (sWeight.Contains(UnitConversion.sKilogramsUnit))
{
sWeight = sWeight.Replace(UnitConversion.sKilogramsUnit, "|");
string[] sParts = sWeight.Split('|');
double? dKilograms = null;
double dKilogramsParsed;
if (sParts.Length >= 2 && double.TryParse(sParts[0].Trim(), out dKilogramsParsed))
{
dKilograms = dKilogramsParsed;
}
sWeight = UnitConversion.KgToLbs(dKilograms).ToString("#.###") + " " + UnitConversion.sPoundUnit;
}
else if (sWeight.Contains(UnitConversion.sPoundUnit))
{
sWeight = sWeight.Replace(UnitConversion.sPoundUnit, "|");
string[] sParts = sWeight.Split('|');
double? dPounds = null;
double dPoundsParsed;
if (sParts.Length >= 2 && double.TryParse(sParts[0].Trim(), out dPoundsParsed))
{
dPounds = dPoundsParsed;
}
sWeight = UnitConversion.LbsToKg(dPounds).ToString("#.###") + " " + UnitConversion.sKilogramsUnit;
}
else
{
sWeight = "";
}
}
else
{
sWeight = "";
}
return sWeight;
}
public static double? CalculateFt(double dFt, double dInch)
{
double? dFeet = null;
if (dFt >= 0 && dInch >= 0 && dInch <= 12)
{
dFeet = dFt + (dInch / 12);
}
return dFeet;
}
public static double KgToLbs(double? dKg)
{
if (dKg == null)
{
return 0;
}
return dKg.Value * 2.20462262;
}
public static double LbsToKg(double? dLbs)
{
if (dLbs == null)
{
return 0;
}
return dLbs.Value / 2.20462262;
}
public static double FtToCm(double? dFt)
{
if (dFt == null)
{
return 0;
}
return dFt.Value * 30.48;
}
public static bool CmToFt(double? dCm, out int? iFt, out int? iInch)
{
if (dCm == null)
{
iFt = null;
iInch = null;
return false;
}
double dCalcFeet = dCm.Value / 30.48;
double dCalcInches = dCalcFeet - Math.Floor(dCalcFeet);
dCalcFeet = Math.Floor(dCalcFeet);
dCalcInches = dCalcInches * 12;
iFt = (int)dCalcFeet;
iInch = (int)dCalcInches;
return true;
}
private static string CleanUnit(string sOriginal, string[] lstReplaceUnits, string sReplaceWithUnit)
{
System.Text.StringBuilder sbPattern = new System.Text.StringBuilder();
foreach (string sReplace in lstReplaceUnits)
{
if (sbPattern.Length > 0)
{
sbPattern.Append("|");
}
sbPattern.Append(sReplace);
}
sbPattern.Insert(0,#"(^|\s)(");
sbPattern.Append(#")(\s|$)");
System.Text.RegularExpressions.Regex rReplace = new System.Text.RegularExpressions.Regex(sbPattern.ToString(), System.Text.RegularExpressions.RegexOptions.IgnoreCase);
sOriginal = rReplace.Replace(sOriginal, sReplaceWithUnit);
/*foreach (string sReplace in lstReplaceUnits)
{
sOriginal = sOriginal.Replace(sReplace, " " + sReplaceWithUnit);
}*/
return sOriginal;
}
private static bool StringHasNumbers(string sText)
{
System.Text.RegularExpressions.Regex rxNumbers = new System.Text.RegularExpressions.Regex("[0-9]+");
return rxNumbers.IsMatch(sText);
}
private static string ReduceSpaces(string sText)
{
while (sText.Contains(" "))
{
sText = sText.Replace(" ", " ");
}
return sText;
}
private static string SeperateNumbers(string sText)
{
bool bNumber = false;
if (!String.IsNullOrEmpty(sText))
{
for (int iChar = 0; iChar < sText.Length; iChar++)
{
bool bIsNumber = (sText[iChar] >= '0' && sText[iChar] <= '9') ||
(sText[iChar] == '.' && iChar < sText.Length - 1 && sText[iChar + 1] >= '0' && sText[iChar + 1] <= '9');
if (iChar > 0 && bIsNumber != bNumber)
{
sText = sText.Insert(iChar, " ");
iChar++;
}
bNumber = bIsNumber;
}
}
return sText;
}
public static string CleanHeight(string sHeight)
{
if (UnitConversion.StringHasNumbers(sHeight))
{
sHeight = SeperateNumbers(sHeight);
sHeight = CleanUnit(sHeight, UnitConversion.lstFootUnits, UnitConversion.sFootUnit);
sHeight = CleanUnit(sHeight, UnitConversion.lstInchUnits, UnitConversion.sInchUnit);
sHeight = CleanUnit(sHeight, UnitConversion.lstCentimeterUnits, UnitConversion.sCentimeterUnit);
sHeight = SeperateNumbers(sHeight);
sHeight = ReduceSpaces(sHeight);
}
else
{
sHeight = "";
}
return sHeight;
}
public static string CleanWeight(string sWeight)
{
if (UnitConversion.StringHasNumbers(sWeight))
{
sWeight = SeperateNumbers(sWeight);
sWeight = CleanUnit(sWeight, UnitConversion.lstOunceUnits, UnitConversion.sOunceUnit);
sWeight = CleanUnit(sWeight, UnitConversion.lstPoundUnits, UnitConversion.sPoundUnit);
sWeight = CleanUnit(sWeight, UnitConversion.lstKilogramUnits, UnitConversion.sKilogramsUnit);
sWeight = SeperateNumbers(sWeight);
sWeight = ReduceSpaces(sWeight);
}
else
{
sWeight = "";
}
return sWeight;
}
}
It should serve you well to build an extension method of string for this purpose. When you build an extension method you attach a new function call to an existing class. In this we are go to attach a method to the 'string' class that returns a double, as the number of millimeters in a given imperial value, PROVIDED that the value can be parsed based on the examples you provide.
using System;
using System.Text;
namespace SO_Console_test
{
static class ConversionStringExtensions
{
//this is going to be a simple example you can
//fancy it up a lot...
public static double ImperialToMetric(this string val)
{
/*
* With these inputst we want to total inches.
* to do this we want to standardize the feet designator to 'f'
* and remove the inch designator altogether.
6 inches
6in
6”
4 feet 2 inches
4’2”
4 ‘ 2 “
3 feet
3’
3 ‘
3ft
3ft10in
3ft 13in (should convert to 4’1”) ...no, should convert to 49 inches, then to metric.
*/
//make the input lower case and remove blanks:
val = val.ToLower().Replace(" ", string.Empty);
//make all of the 'normal' feet designators to "ft"
string S = val.Replace("\'", "f").Replace("feet", "f").Replace("ft", "f").Replace("foot", "f").Replace("‘", "f").Replace("’", "f");
//and remove any inch designator
S = S.Replace("\"", string.Empty).Replace("inches", string.Empty).Replace("inch", string.Empty).Replace("in", string.Empty).Replace("“", string.Empty).Replace("”", string.Empty);
//finally we have to be certain we have a number of feet, even if that number is zero
S = S.IndexOf('f') > 0 ? S : "0f" + S;
//now, any of the inputs above will have been converted to a string
//that looks like 4 feet 2 inches => 4f2
string[] values = S.Split('f');
int inches = 0;
//as long as this produces one or two values we are 'on track'
if (values.Length < 3)
{
for (int i = 0; i < values.Length; i++)
{
inches += values[i] != null && values[i] != string.Empty ? int.Parse(values[i]) * (i == 0 ? 12 : 1) : 0 ;
}
}
//now inches = total number of inches in the input string.
double result = inches * 25.4;
return result;
}
}
}
With that in place "ImperialToMetric()" becomes a method of any string, and can be invoked anywhere the extension containing class ConversionStringExtensions is referenced. You can use it like:
namespace SO_Console_test
{
class Program
{
static void Main(string[] args)
{
showConversion();
Console.ReadLine();
}
private static void showConversion()
{
//simple start:
Console.WriteLine("6ft 2\"".ImperialToMetric().ToString() + " mm");
//more robust:
var Imperials = new List<string>(){"6 inches",
"6in",
"6”",
"4 feet 2 inches",
"4’2”",
"4 ‘ 2 “",
"3 feet",
"3’",
"3 ‘",
"3ft",
"3ft10in",
"3ft 13in"};
foreach (string imperial in Imperials)
{
Console.WriteLine(imperial + " converted to " + imperial.ImperialToMetric() + " millimeters");
}
}
}
Obviously, at this point a call to "Fred".ImperialToMetric is not going to play nice. You will need to had error handling and perhaps some options to turn 1234 mm 1.234 km etc. but once you flush this out you have a method you can use where ever you choose.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ConsoleApplication5
{
class Program
{
static void Main(string[] args)
{
double km,m,f,i,cm;
Console.WriteLine("The distance between karachi and lahore in (kilometer)km is=");
km = Convert.ToInt32(Console.ReadLine());
m = km * 1000;
Console.WriteLine("The distance between karachi and lahore in meter(m) is="+m);
f = km * 3280.84;
Console.WriteLine("The distance between karachi and lahore in feet(f) is="+f);
i = km * 39370.1;
Console.WriteLine("The distance between karachi and lahore in inches(i) is="+i);
cm = m * 100;
Console.WriteLine("The distance between karachi and lahore in centimeter(cm) is="+cm);
Console.ReadLine();
}
}
}
An extension for string I wrote only to find out that there is already a solution here :) The only thing left to do is to replace "feet", "ft", "’" to "'" and "inches", "inch", "in", "“", "\"" to "''".
using System;
namespace CustomExtensions
{
public static class StringExtension
{
const float mPerFeet = 30.48f / 100;
const float mPerInch = 2.54f / 100;
// input options:
// 5'
// 5'6''
// 18''
// 24''
// 5'6
// 5 ' 6 ''
// 5' 6''
// corner cases:
// '' will return 0
// 5''6'' will interpret as 5'6''
// 5'6' will interpret as 5'6''
// 6 will interpret as 6''
// 6''' will interpret as 6''
public static float MetersFromFeetInches(this string feetInches)
{
float feet = 0;
float inches = 0;
string[] separators = new string[] { "'", "''", " " };
string[] subs = feetInches.Split(separators, StringSplitOptions.RemoveEmptyEntries);
if (subs.Length == 1)
{
if (feetInches.Trim().EndsWith("''"))
{
float.TryParse(subs[0], out inches);
}
else if (!feetInches.Trim().EndsWith("''") && !feetInches.Trim().EndsWith("'"))
{
float.TryParse(subs[0], out inches);
}
else
{
float.TryParse(subs[0], out feet);
}
}
else if (subs.Length > 1)
{
float.TryParse(subs[0], out feet);
float.TryParse(subs[1], out inches);
}
return feet * mPerFeet + inches * mPerInch;
}
}
}

Categories

Resources