- Home /
Breaking up a string every A,B,C,D and store value behind it
I have a script that writes and reads lines from a file, consisting of A,B,C,D positions. Now as far as writing goes, I output these 4 positions every line to a file. So the format per line will be: A"float"B"float"C"float"D"float" or: A-39.50768B78.55463C44.15681D-122.7114
when reading the file, i put each line into an array as a string, so that i can access each string at any time i need. Now i need to have those positions read to apply them to a model. So what i'm looking for is to read the string, check for the character A, then put the numbers after that to a array of A positions, then the same for B and so on.. So the question is.. how do i do this.. i've been looking around, but couldn't find a situation like this.
Here's my code, it might be a bit messy as i do almost everything in one file so far, but the saving and reading functions are at the bottom.
//public var GUIObj : GameObject;
//public var guiScr = GameObject.GetComponent(GUIObj, "rotateobjec");
//public var guiScr = GUIObj.GetComponent(rotateobjec);
//Arm variables
import System;
import System.IO;
public var MakeLine = false;
public var MakeFile = false;
public var base_height:float = 50.0;
public var arm_1_length:float = 100.0;
public var arm_2_length:float = 100.0;
public var grip_length:float = 60.0;
public var grip_angle_deg:float = 0.0;
public var grip_angle_deg_02:float = 0.0;
//Goal Position
public var target : GameObject;
public var xPos = 0.0;
public var yPos = 0.0;
public var zPos = 0.0;
//ArmRotations
public var Angle1 = 0.0;
public var Angle2 = 0.0;
public var Angle3 = 0.0;
public var Angle4 = 0.0;
//attach script on all joints, in the editor select true or false for the joint
public var applyAngle1 = true;
public var applyAngle2 = false;
public var applyAngle3 = false;
public var applyAngle4 = false;
public var applyAngle5 = false;
public var distance_offset = 4.6;
//define offsets
public var grip_offset_t = 10;
public var arm1_angle_offset = 90;
public var arm2_angle_offset = 180;
public var TargetOffsetX:float = 0.0;
public var TargetOffsetZ:float = 0.0;
public var XR = 0.0;
public var YR = 0.0;
public var D = 0.0;
//error detect vars
public var maxDist = 0;
public var showAlert = false;
var ALines = new Array ();
var BLines = new Array ();
var CLines = new Array ();
var DLines = new Array ();
public var ReadLines = new Array ();
var fileName = "MyFile.txt";
var openFile = false;
function Start () {maxDist=arm_1_length+arm_2_length+grip_length;}
function Update () {
if(openFile)
{
OpenFile(fileName);
openFile = false;
}
if(MakeFile)
{
SaveLines();
MakeFile = false;
}
var targetPos = target.transform.position;
zPos = targetPos.z;
yPos = targetPos.y;
xPos = targetPos.x;
//guiScr
// grip_angle_deg = guiScr.hSliderValue0;
// grip_angle_deg_02 = guiScr.hSliderValue1;
//DoIK(zPos-TargetOffsetZ,xPos-TargetOffsetX,yPos,grip_angle_deg);
ErrorCheck(zPos-TargetOffsetZ,xPos-TargetOffsetX,yPos,grip_angle_deg);
//guiScr = GUIObj.GetComponent(rotateobjec);
}
function ErrorCheck (x:float,y:float,z:float,grip_angle_deg:float)
{
XR = Mathf.Sqrt((x * x) + (y * y));
YR = Mathf.Sqrt((x * x) + (z * z));
var ZR = 0;
if(XR < maxDist)
{
DoIK(zPos-TargetOffsetZ,xPos-TargetOffsetX,yPos,grip_angle_deg);
}
else{ showAlert = true;}
}
function DoIK (x:float,y:float,z:float,grip_angle_deg:float)
{
//precalculation
var arm1sq = arm_1_length * arm_1_length;
var arm2sq = arm_2_length * arm_2_length;
//convert grip angle degrees to radians for use in calculations
var grip_angle_rad = grip_angle_deg * Mathf.Deg2Rad;
//calculate base angle
var base_angle_rad = Mathf.Atan2(x, y);
//calculate new distance
D = Mathf.Sqrt((x * x) + (y * y));
//calculate d and z offset based on grip angle and length
var z_off = Mathf.Asin(grip_angle_rad) * grip_length;
var d_off = Mathf.Acos(grip_angle_rad) * grip_length;
//error checking(needs work)
if(d_off < maxDist)
{
//get wrist position
var wrist_z = (z - z_off) - base_height;
var wrist_d = (D - d_off) + distance_offset;
//calculate arm angles using inverse kinematics
var b_s = (wrist_z * wrist_z) + (wrist_d * wrist_d);
var b_r = Mathf.Sqrt(b_s);
var q1 = Mathf.Atan2(wrist_z, wrist_d);
var q2 = Mathf.Acos(((arm1sq - arm2sq) + b_s) / (2 * arm_1_length * b_r));
var angle_1 = q1 + q2;
var angle_2 = Mathf.Acos((arm1sq + arm2sq - b_s) / (2 * arm_1_length * arm_2_length));
var angle_3 = grip_angle_rad - angle_1 - angle_2;
}
//set radians back to degrees!
Angle1 = base_angle_rad * Mathf.Rad2Deg;
Angle2 = angle_1 * Mathf.Rad2Deg;
Angle3 = angle_2 * Mathf.Rad2Deg;
Angle4 = angle_3 * Mathf.Rad2Deg;
if(MakeLine)
{
MakeLines(Angle1,Angle2,Angle3,Angle4);
MakeLine = false;
}
//display angles to model
if(float.IsNaN(Angle1) || float.IsNaN(Angle2) || float.IsNaN(Angle3) || float.IsNaN(Angle4))
{
showAlert = true;
}
else{
ApplyToModel(Angle1,Angle2,Angle3,Angle4);
showAlert = false;
}
}
function ApplyToModel (angle1:float,angle2:float,angle3:float,angle4:float)
{
/* make euler variables */
var target1 = Quaternion.Euler (0, -angle1, 0);
var target2 = Quaternion.Euler (0, -angle1, angle2-arm1_angle_offset);
var target3 = Quaternion.Euler (0, -angle1, (angle3+(angle2-arm1_angle_offset))+arm2_angle_offset);
var target4 = Quaternion.Euler (grip_angle_deg_02, -angle1, (angle4+(angle3+(angle2-90)))+grip_offset_t);
var target5 = Quaternion.Euler (0, grip_angle_deg_02,0);
/* apply rotation vectors to object */
if(applyAngle1){transform.rotation = target1;}
if(applyAngle4){transform.rotation = target4;}
if(applyAngle3){transform.rotation = target3;}
if(applyAngle2){transform.rotation = target2;}
if(applyAngle5){transform.localRotation = target5;}
}
function OnGUI () {
var bString = Angle1.ToString();
var a1String = Angle2.ToString();
var a2String = Angle3.ToString();
var tString = Angle4.ToString();
var objectDist = XR.ToString();
GUI.Label (Rect (Screen.width-300, 10, 100, 20), "Base Angle: ");
GUI.Label (Rect (Screen.width-200, 10, 100, 20), bString);
GUI.Label (Rect (Screen.width-300, 30, 100, 20), "Arm 1 Angle: ");
GUI.Label (Rect (Screen.width-200, 30, 100, 20), a1String);
GUI.Label (Rect (Screen.width-300, 50, 100, 20), "Arm 2 Angle: ");
GUI.Label (Rect (Screen.width-200, 50, 100, 20), a2String);
GUI.Label (Rect (Screen.width-300, 70, 100, 20), "Tool Angle: ");
GUI.Label (Rect (Screen.width-200, 70, 100, 20), tString);
GUI.Label (Rect (Screen.width-300, 90, 100, 20), "Object Distance: ");
GUI.Label (Rect (Screen.width-200, 90, 100, 20), objectDist);
if(showAlert)
{
GUI.Label (Rect ((Screen.width/2)-50, (Screen.height/2)-10, 100, 20), "ERROR");
GUI.Label (Rect ((Screen.width/2)-90, (Screen.height/2)+10, 180, 20), "ARM LIMITS REACHED");
}
}
function MakeLines (aval:float,bval:float,cval:float,dval:float)
{
//every push also extends lenght of array, push always becomes the highest number in the array
//all array's get one push a time, so all lengths are the same
ALines.Push (aval);
BLines.Push (bval);
CLines.Push (cval);
DLines.Push (dval);
print(ALines.length);
}
function SaveLines ()
{
if (File.Exists(fileName))
{
Debug.Log(fileName+" already exists.");
return;
}
var sr = File.CreateText(fileName);
for(var i = 0; ALines.length > i; i++)
{
sr.WriteLine ("A " + ALines[i] + " B " + BLines[i] + " C " + CLines[i] + " D " + DLines[i]);
}
sr.Close();
}
function OpenFile(file : String)
{
if(File.Exists(file))
{
var sr = File.OpenText(file);
var line = sr.ReadLine();
while(line != null)
{
ReadLines.push(line);
Debug.Log(line);
line = sr.ReadLine();
}
}else{
Debug.Log("Could not open the file" + file);
}
}
I might have found a way to do it, at least i think i'm heading the right direction. Still couldn't find some reasonable examples or anything. Anyhow, i wrote a function that loops trough the array of lines, each time setting a string var for that line, then checking each character of that string with var j, then if the character is the same as A or B etc, then set a var Apos or Bpos etc, to be the same as j. Now this is all i have so far, the next obstacle is getting the numbers on the positions in between to be put as a float into an array..
To clarify a bit, here's the function:
function ReadRayCode ()
{
var Apos : int;
var Bpos : int;
var Cpos : int;
var Dpos : int;
for(var i = 0; ReadLines.length > i; i++ )
{
var s : String = ReadLines[i];
for(var j = 0; s.length > j; j++)
{
var c : char = s[j];
if(c == "A")
{
Apos = j;
print("Found A: " + Apos);
}
if(c == "B")
{
Bpos = j;
print("Found B: " + Bpos);
}
if(c == "C")
{
Cpos = j;
print("Found C: " + Cpos);
}
if(c == "D")
{
Dpos = j;
print("Found D: " + Dpos);
}
//else{print("NOPES");}
}
}
}
Answer by Napalm1432 · Feb 07, 2017 at 01:41 PM
EDIT: please read the comments on the other answer
Okay, after some trial and error, and some funky get around, i managed to do it! Right now it's just printing the seperate values to the console, but at least they're seperate. From here on out it's simply putting them inside a array for each corresponding letter. might have to convert string to float. Anyhow here's the code for those interested in the same thing. It's simply an extra function build on the first code i published.
function ReadRayCode ()
{
var Apos : int;
var Bpos : int;
var Cpos : int;
var Dpos : int;
for(var i = 0; ReadLines.length > i; i++ )
{
var s : String = ReadLines[i];
print("STRING: " + s);
for(var j = 0; s.length > j; j++)
{
var c : char = s[j];
if(c == "A"){
Apos = j;
}
if(c == "B"){
Bpos = j;
}
if(c == "C"){
Cpos = j;
}
if(c == "D"){
Dpos = j;
}
}
print("A VALUE:" + s.Substring(Apos+1, Bpos-1));
print("B VALUE:" + s.Substring(Bpos+1, (Cpos-Bpos)-1));
print("C VALUE:" + s.Substring(Cpos+1, (Dpos-Cpos)-1));
print("D VALUE:" + s.Substring(Dpos+1));
}
}
Answer by Scoutas · Feb 07, 2017 at 01:41 AM
What you need to do, is to split the string on the B, C and D letters. There's a handy method called Split()
which you call on a string you want to split. Inside it, you pass in the things you want it to split by (in this example, A, B, C, D. There's a case to be made that you don't need A in front of the strings, and I've explained it in the comments in the code).
After you've done it, you need to Parse it into a float. You just call it and pass in the string you want to convert into a float. There might be some problems and as mentioned before - mentioned them inside of the comments in the code example.
EDIT: Acutally, I would suggest just splitting them with a comma or something, because one way or the other, it will put the split string into an array in a sorted manner (e.g. if the string was "-1,2,7,4"
after splitting by a ,
they would be put into an array in that order of -1
, 2
, 7
, 4
and then it would be your job to add them to arrays that you like and such.)
public class SplitTest: MonoBehaviour {
string st = "A-39.50768B78.55463C44.15681D-122.7114";
void Start(){
// Sadly, this will create one empty string, because after splitting after letter A
// it returns everything that was before it. You could omit the A in front of the
// string and it would work just fine.
string[] strings = st.Split ('A', 'B', 'C', 'D');
foreach (string s in strings) {
// Now we're looping through every single string that's been generated by splitting it.
// Because it has created an empty string, we have to check if it's not an empty string
// cuz float.Parse will throw a fit if we try passing an empty string to it.
if (s.Length > 0) {
float k = float.Parse (s);
}
}
}
}
Although you have been a great help when it comes to the code, however, our methods are a bit different, i use the A B C D as pointers, not as seperators. What i mean is, the string could bbe ABCD, but could also be just ABD, so i can't just break it up every letter. Now i know i could also put in a empty value for C, but this goes a bit further then just ABCD I also want to be able to load in .gcode files ( which i partially can now) which uses G X Y Z E but the lines look like this: G X Y Z G X Y G X Y G X Y E G X Y G X Y Z E
and there's no altering how gcode is written. So the way i want to to the abcd strings, i also want for xyz strings, just to make it a bit more universal.
So in conclusion, i'm pretty far right now, although right now, there will still be an issue with for example the C missing, so i still need a way to fix that.
just adding to the last comment, i might give the floats a fixed length, so they always take the same space in the array, so when i find B i can just count that set number in the string. so 45.0 could become 45.00000000 and 198.5 could become 198.5000000 giving both values a same length. Now i'm just theorizing here, so i'm not even sure if that is possible...
Answer by ASPePeX · Feb 08, 2017 at 04:24 PM
Regular expressions can solve this, here a little example how to parse your format:
using System.Text.RegularExpressions;
using UnityEngine;
public class regoexo : MonoBehaviour {
private string line = "A-39.50768B78.55463C44.15681D-122.7114";
void Start ()
{
MatchCollection matches = Regex.Matches(line, @"([ABCD]-?\d*\.\d*)");
foreach (var match in matches)
{
Debug.Log(match);
}
}
}
This results in 4 strings like "A-39.50768", so you still have to split of the letter and parse the float. I'm not sure how good the C# implementation of RegExes is, might not be a good idea to use them in an update loop.
Your answer
Follow this Question
Related Questions
Split() into a fixed length array? 1 Answer
Java List. 0 Answers
Type function(): Object[] does not support Slicing 1 Answer