숫자 범위 추출 및 확장

C# 2021. 11. 3. 17:46

https://yamoe.tistory.com/384

 

 

 

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;

namespace test
{

    // test 클래스
    public class TestLongRangeExpression
    {
        public static void Test()
        {
            string str = "-6,-3,-2,-1,3,4,5,7,8,9,10,11,14,15,17,18,19,20";
            string compressStr = LongRangeExpression.Compress(str);
            string uncompressStr = LongRangeExpression.UncompressToString(compressStr);

            Console.WriteLine(compressStr);
            Console.WriteLine(uncompressStr);
            Console.WriteLine(str == uncompressStr);
        }
    }


    // long 형에 대한 범위 표현식 변환
    // ex>
    //   compress : "0,1,2" -> "0~2"
    //   uncompress : "0~2" -> "0,1,2"
    public class LongRangeExpression
    {
        private static readonly Regex s_RegexForUncompress = new Regex(@"(?<f>-?\d+)~(?<s>-?\d+)|(-?\d+)");

        // "0,1,2" -> "0~2"
        public static string Compress(string str)
        {
            return Compress(str.Split(',').Select(long.Parse).ToList());
        }

        // "0,1,2" -> "0~2"
        public static string Compress(List<long> list)
        {
            return string.Join(
                ",",
                Compress(list as IEnumerable<long>)
                .Select(r => r.end == r.start ? $"{r.start}" : $"{r.start}~{r.end}"));
        }

        // "0,1,2" -> "0~2"
        public static IEnumerable<(long start, long end)> Compress(IEnumerable<long> numbers)
        {
            if (numbers == null) yield break;

            var e = numbers.GetEnumerator();
            if (!e.MoveNext())
            {
                yield break;
            }

            long start = e.Current;
            long end = start;

            while (e.MoveNext())
            {
                if (e.Current - end != 1)
                {
                    if (end - start == 1)
                    {
                        yield return (start, start);
                        yield return (end, end);
                    }
                    else
                    {
                        yield return (start, end);
                    }
                    start = e.Current;
                }
                end = e.Current;
            }
            yield return (start, end);
        }


        // "0~2" -> "0,1,2"
        public static string UncompressToString(string str)
        {
            return string.Join(",", UncompressToList(str));
        }

        // "0~2" -> "0,1,2"
        public static List<long> UncompressToList(string str)
        {
            List<long> list = new List<long>();

            MatchCollection matches = s_RegexForUncompress.Matches(str);

            foreach (var m in matches.OfType<Match>())
            {
                if (m.Groups[1].Success)
                {
                    list.Add(Convert.ToInt64(m.Value));
                    continue;
                }

                long start = Convert.ToInt64(m.Groups["f"].Value);
                long end = Convert.ToInt64(m.Groups["s"].Value) + 1;

                for (long i = start; i < end; i++)
                {
                    list.Add(i);
                }
            }

            return list;
        }

    }
}