有没有更好的方法使用 LINQ 来分割这个字符串?

9

我有一串经纬度坐标,希望将其拆分为经度和纬度对。感谢stackoverflow,我已经能够使用linq将其拆分为多维字符串数组。是否有一种方法可以直接将该字符串拆分为接受经度和纬度的对象,而不是先创建字符串数组再创建对象?

string segment = "51.54398, -0.27585;51.55175, -0.29631;51.56233, -0.30369;51.57035, -0.30856;51.58157, -0.31672;51.59233, -0.3354"

string[][] array = segment.Split(';').Select(s => s.Split(',')).ToArray();
foreach (string[] pair in array)
{
//create object here
}

1
使用LINQ分割字符串(几乎?)从来都不是一个好方法。话虽如此,System.Text.RegularExpressions才是你想要的。 - sehe
1
你字符串末尾的“-0.3354”,“London:484”是什么意思? - Tim Schmelter
2
@sehe:对于这样一个琐碎的任务使用正则表达式是杀鸡焉用牛刀。如果您知道输入的格式是恒定的,并且通过拆分容易解析,那么应该使用拆分而不是正则表达式。 - Ed S.
@NullReference 已添加 **一个带演示的答案**。 在 **IdeOne.com 上实时查看**。 - sehe
@EdS。见仁见智。我不明白为什么需要在两个评论中基本上重复你的观点。显然,使用正则表达式进行解析比拆分进行输入检查更加严格。让原帖选择。编辑还要注意我的答案似乎是唯一一个关注数字解析而不假设美国文化的答案。 - sehe
显示剩余7条评论
7个回答

24

你已经很接近了。类似于以下内容或许会有所帮助:

var pairSequence = segment.Split(';')
        .Select(s => s.Split(','))
        .Select(a => new { Lat = double.Parse(a[0]), Long = double.Parse(a[1]) });

@Alex 当然,这取决于你实际需要的类型。你明白的。 - Mehrdad Afshari
该死。我正在写几乎完全相同的东西。赞。 - Robert P

6
假设您有一个名为Coordinate的类,并且其中包含一个public Coordinate(double x, double y)构造函数,你可以这样做:
Coordinate[] result = segment
    .Split(';')
    .Select(s => s.Split(','))
    .Select(a => new Coordinate(x: double.Parse(a[0], NumberStyles.Number),
                                y: double.Parse(a[1], NumberStyles.Number))
    .ToArray();

或同等地
var query = from item in segment.Split(';')
            let parts = item.Split(',')
            let x = double.Parse(parts[0], NumberStyles.Number)
            let y = double.Parse(parts[1], NumberStyles.Number)
            select new Coordinate(x, y);

Coordinate[] result = query.ToArray();

3
你可以这样做:
public class GeoCoordinates {
  public decimal Latitude { get; set; }
  public decimal Longitude { get; set; }

  public GeoCoordinates( string latLongPair ) {
    decimal lat, lng;
    var parts = latLongPair.Split( new[] { ',' } );
    if( decimal.TryParse( parts[0], out lat ) &&
      decimal.TryParse( parts[1], out lng ) ) {
      Latitude = lat;
      Longitude = lng;
    } else {
      // you could set some kind of "ParseFailed" or "Invalid" property here
    }
  }
}

然后,您可以这样创建一个GeoCoordinate类的集合:
var coords = segment.Split( new[] {';'} ).Select( x => new GeoCoordinates( x ) );

嘿...StackOverflow 可以是一场相当激烈的竞赛,不是吗? - Ethan Brown

3
这是一个“有点”好的片段,其中包括:
  • 预编译正则表达式
  • LINQ 到匿名类型的映射
  • 文化感知(正确的)数字解析和打印
在现实生活中,您可能希望提取某些代码(例如数字解析)。
Ideone.com上实时查看。
using System;
using System.Linq;
using System.Text.RegularExpressions;
using System.Globalization;

namespace SODemo
{
    class MainClass
    {
        private static readonly CultureInfo CInfo = CultureInfo.CreateSpecificCulture("en-US");

        public static void Main (string[] args)
        {
            string segment = "51.54398, -0.27585;51.55175, -0.29631;51.56233, -0.30369;51.57035, -0.30856;51.58157, -0.31672;51.59233, -0.3354";

            var re = new Regex(@"\s*(?<lat>[-+]?[0-9.]+),\s*(?<lon>[-+]?[0-9.]+)\s*;", RegexOptions.Compiled | RegexOptions.CultureInvariant | RegexOptions.IgnoreCase);

            var locations = re.Matches(segment).Cast<Match>().Select(m => new 
            {
                Lat  = decimal.Parse(m.Groups["lat"].Value, CInfo),
                Long = decimal.Parse(m.Groups["lon"].Value, CInfo),
            });

            foreach (var l in locations)
                Console.WriteLine(l);
        }
    }
}

输出:

{ Lat = 51,54398, Long = -0,27585 }
{ Lat = 51,55175, Long = -0,29631 }
{ Lat = 51,56233, Long = -0,30369 }
{ Lat = 51,57035, Long = -0,30856 }
{ Lat = 51,58157, Long = -0,31672 }

2

你是否必须使用LINQ?其实,你可以通过标准字符串拆分功能完成所有操作:

string[] pairsOfCoords = segment.Split(';');
List<CoordsObject> listOfCoords = new List<CoordsObject>();
foreach (string str in pairsOfCoords)
{
  string[] coords = str.Split(',');
  CoordsObject obj = new CoordsObject(coords[0], coords[1]);
  listOfCoords.Add(obj);
}

1
是啊,但使用LINQ后代码变得更加简洁。 :) - Robert P
1
@RobertP:嗯,我想这是主观的。这看起来对我来说非常简单和清晰。 - Ed S.

1

我可能会添加更多内容。感谢dtb的开头,已点赞。如果将解析函数拆分出来,您可以更清晰地处理错误条件,例如数组中元素数量不正确或无法解析为十进制的元素。

Coordinate[] result = segment
.Split(';')
.Select(s => s.Split(','))
.Select(BuildCoordinate)
.ToArray();

Coordrinate BuildCoordinate(string[] coords)
{
    if(coords.Length != 2)
        return null;

    return new Coordinate(double.Parse(a[0].Trim(), double.Parse(a[1]);
}

1
一些任务用传统的方式解决会更容易:

var split = segment.Split();
var coordinates = new List<Coordinate>(split.Length);
foreach(string s in split)
{
    coordinates.Add(new Coordinate(s));
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接