问题
I want that in Rect.rectangles under the transform property instead to have the string "matrix(0.87142591,0.49052715,-0.49052715,0.87142591,0,0)" to have 2 properties like transform and transform1 and each one will have a number for example: transform "0.12345678" transform1 "1.12345678"
private void Parse()
{
XDocument document = XDocument.Load(@"C:\Users\mysvg\Documents\my.svg");
Rect.rectangles = document.Descendants().Where(x => x.Name.LocalName == "rect").Select(x => new Rect()
{
style = Rect.GetStyle((string)x.Attribute("style")),
id = (string)x.Attribute("id"),
width = (double)x.Attribute("width"),
height = (double)x.Attribute("width"),
x = (double?)x.Attribute("width"),
y = (double?)x.Attribute("width"),
transform = x.Attribute("transform".Substring(18, 43)) == null ? "" : (string)x.Attribute("transform".Substring(18, 43))
}).ToList();
}
And the Rect class:
public class Rect
{
public static List<Rect> rectangles { get; set; }
public Dictionary<string, string> style { get; set; }
public string id { get; set; }
public double width { get; set; }
public double height { get; set; }
public double? x { get; set; }
public double? y { get; set; }
public string transform { get; set; }
public static Dictionary<string, string> GetStyle(string styles)
{
string pattern = @"(?'name'[^:]+):(?'value'.*)";
string[] splitArray = styles.Split(new char[] { ';' });
Dictionary<string, string> style = splitArray.Select(x => Regex.Match(x, pattern))
.GroupBy(x => x.Groups["name"].Value, y => y.Groups["value"].Value)
.ToDictionary(x => x.Key, y => y.FirstOrDefault());
return style;
}
}
I'm trying to use substring but getting out of range exception.
ArgumentOutOfRangeException: Cannot exceed length of string
On the line:
transform = x.Attribute("transform".Substring(18, 43)) == null ? "" : (string)x.Attribute("transform".Substring(18, 43))
The string is:
transform="matrix(0.40438612,-0.91458836,0.92071162,0.39024365,0,0)"
And i want to get only the first two numbers: 0.40438612,-0.91458836
Update:
I found also a way to do it using foreach:
private void Parse()
{
XDocument document = XDocument.Load(@"C:\Users\mysvg\Documents\my.svg");
Rect.rectangles = document.Descendants().Where(x => x.Name.LocalName == "rect").Select(x => new Rect()
{
style = Rect.GetStyle((string)x.Attribute("style")),
id = (string)x.Attribute("id"),
width = (double)x.Attribute("width"),
height = (double)x.Attribute("width"),
x = (double?)x.Attribute("width"),
y = (double?)x.Attribute("width"),
transform = x.Attribute("transform") == null ? "" : (string)x.Attribute("transform")
}).ToList();
string t = null;
foreach(Rect rect in Rect.rectangles)
{
if (rect.transform != null && rect.transform != "")
{
t = rect.transform.Substring(7, 21);
}
}
}
But i don't want to do it after the new Rect() { I want to do the first two numbers extraction on the line:
transform = x.Attribute("transform") == null ? "" : (string)x.Attribute("transform")
The reason is that i have in the bottom of the code a class:
public class Rect
{
public static List<Rect> rectangles { get; set; }
public Dictionary<string, string> style { get; set; }
public string id { get; set; }
public double width { get; set; }
public double height { get; set; }
public double? x { get; set; }
public double? y { get; set; }
public string transform { get; set; }
public static Dictionary<string, string> GetStyle(string styles)
{
string pattern = @"(?'name'[^:]+):(?'value'.*)";
string[] splitArray = styles.Split(new char[] { ';' });
Dictionary<string, string> style = splitArray.Select(x => Regex.Match(x, pattern))
.GroupBy(x => x.Groups["name"].Value, y => y.Groups["value"].Value)
.ToDictionary(x => x.Key, y => y.FirstOrDefault());
return style;
}
}
And i want that the property transform to hold/contain the two numbers already.
And another small problem how can i extract the first two numbers if for example one of the numbers have -(minus) in the start for example if transform contain the string: "matrix(0.40438612,-0.91458836,0.92071162,0.39024365,0,0)"
If one of the two numbers have minus in the start or both of them have minus in the start the Substring(7, 21) will not work. I need somehow to get in any case the first two numbers. But the main issue is how to extract the numbers directly from the attribute already.
回答1:
Are you looking for regular expressions?
using System.Globalization;
using System.Linq;
using System.Text.RegularExpressions;
...
string transform = "matrix(0.40438612,-0.91458836,0.92071162,0.39024365,0,0)";
double[] result = Regex
.Matches(transform, @"-?[0-9]*\.?[0-9]+")
.OfType<Match>()
.Take(2)
.Select(match => double.Parse(match.Value, CultureInfo.InvariantCulture))
.ToArray();
回答2:
Without regular expression you can get the part of the string starting right after the first parenthesis and then split it using the comma:
var transform="matrix(0.40438612,-0.91458836,0.92071162,0.39024365,0,0)";
var numbers = transform.Substring(transform.IndexOf('(') + 1).Split(',');
Console.WriteLine(double.Parse(numbers[0]));
Console.WriteLine(double.Parse(numbers[1]));
Please add error handling.
<== Fiddle Me ==>
回答3:
Solution:
private void Parse()
{
XDocument document = XDocument.Load(@"C:\Users\mysvg\Documents\my.svg");
Rect.rectangles = document.Descendants().Where(x => x.Name.LocalName == "rect").Select(x => new Rect()
{
style = Rect.GetStyle((string)x.Attribute("style")),
id = (string)x.Attribute("id"),
width = (double)x.Attribute("width"),
height = (double)x.Attribute("width"),
x = (double?)x.Attribute("width"),
y = (double?)x.Attribute("width"),
transform = x.Attribute("transform") == null ? "" : (string)x.Attribute("transform")
}).ToList();
for(int i = 0; i < Rect.rectangles.Count; i++)
{
if (Rect.rectangles[i].transform != null && Rect.rectangles[i].transform != "")
{
Rect.rectangles[i].transform = Rect.rectangles[i].transform.Substring(7, 21);
}
}
}
回答4:
Here is the best answer
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
using System.Text.RegularExpressions;
namespace ConsoleApplication1
{
class Program
{
const string FILENAME = @"c:\temp\test.xml";
static void Main(string[] args)
{
XDocument doc = XDocument.Load(FILENAME);
Rect.rectangles = doc.Descendants().Where(x => x.Name.LocalName == "rect").Select(x => new Rect()
{
style = Rect.GetStyle((string)x.Attribute("style")),
id = (string)x.Attribute("id"),
width = (double)x.Attribute("width"),
height = (double)x.Attribute("width"),
x = (double?)x.Attribute("width"),
y = (double?)x.Attribute("width"),
transform = x.Attribute("transform") == null ? null : (object)Rect.GetTransform((string)x.Attribute("transform"))
}).ToList();
}
}
public class Rect
{
public static List<Rect> rectangles { get; set; }
public Dictionary<string, string> style { get; set; }
public string id { get; set; }
public double width { get; set; }
public double height { get; set; }
public double? x { get; set; }
public double? y { get; set; }
public object transform { get; set; }
public static Dictionary<string, string> GetStyle(string styles)
{
string pattern = @"(?'name'[^:]+):(?'value'.*)";
string[] splitArray = styles.Split(new char[] { ';' });
Dictionary<string, string> style = splitArray.Select(x => Regex.Match(x, pattern))
.GroupBy(x => x.Groups["name"].Value, y => y.Groups["value"].Value)
.ToDictionary(x => x.Key, y => y.FirstOrDefault());
return style;
}
public static KeyValuePair<double, double> GetTransform(string matrix)
{
string pattern = @"[-+]?\d+\.\d+";
MatchCollection matches = Regex.Matches(matrix, pattern);
KeyValuePair<double, double> kp = new KeyValuePair<double, double>(
double.Parse(matches[0].Value),
double.Parse(matches[0].Value)
);
return kp;
}
}
}
来源:https://stackoverflow.com/questions/44347790/how-can-i-parse-only-the-numbers-from-the-string