ヒープメモリを使わずに文字列分割

2026年9月4日金曜日

.NET C#

環境

.NET 10、C#

コード

一例として、2つのパスが親子であるかどうかを判定するコードを作りました。ReadOnlySpan<T>の場合、分割の結果をRangeの列挙子で返すところがキーですね。

using Path = System.IO.Path;

namespace Common.IO
{
    /// <summary>
    /// パス情報を表す string の操作を提供します。
    /// </summary>
    public static class PathHelper
    {
        private static readonly char[] s_directorySeparatorChars = Path.DirectorySeparatorChar == Path.AltDirectorySeparatorChar
            ? [Path.DirectorySeparatorChar]
            : [Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar];

        /*
        public static bool IsParentOf(string parentPath, string childPath)
        {
            if (string.IsNullOrEmpty(parentPath) || string.IsNullOrEmpty(childPath))
            {
                return false;
            }

            parentPath = Path.TrimEndingDirectorySeparator(parentPath);
            childPath = Path.TrimEndingDirectorySeparator(childPath);

            if (parentPath.Length >= childPath.Length)
            {
                return false;
            }

            string[] parentSegments = parentPath.Split(s_directorySeparatorChars);
            string[] childSegments = childPath.Split(s_directorySeparatorChars);

            return (parentSegments.Length < childSegments.Length)
                && childSegments.Take(parentSegments.Length).SequenceEqual(parentSegments, StringComparer.OrdinalIgnoreCase);
        }
        */

        /// <summary>
        /// parentPath が childPath の親ディレクトリーであるかどうかを返します。
        /// </summary>
        /// <param name="parentPath"></param>
        /// <param name="childPath"></param>
        /// <returns></returns>
        public static bool IsParentOf(ReadOnlySpan<char> parentPath, ReadOnlySpan<char> childPath)
        {
            if (parentPath.IsEmpty || childPath.IsEmpty)
            {
                return false;
            }

            parentPath = Path.TrimEndingDirectorySeparator(parentPath);
            childPath = Path.TrimEndingDirectorySeparator(childPath);

            if (parentPath.Length >= childPath.Length)
            {
                return false;
            }

            // パスを区切り文字で分割して、childPath の先頭に parentPath が含まれているかどうかを判断します。
            MemoryExtensions.SpanSplitEnumerator<char> parentSegments = parentPath.SplitAny(s_directorySeparatorChars);
            MemoryExtensions.SpanSplitEnumerator<char> childSegments = childPath.SplitAny(s_directorySeparatorChars);

            while (parentSegments.MoveNext())
            {
                if (!childSegments.MoveNext())
                {
                    return false;
                }

                ReadOnlySpan<char> parentSegment = parentPath[parentSegments.Current];
                ReadOnlySpan<char> childSegment = childPath[childSegments.Current];

                if (!parentSegment.Equals(childSegment, StringComparison.OrdinalIgnoreCase))
                {
                    return false;
                }
            }

            return childSegments.MoveNext();
        }
    }
}
rommxbbu6v6

.NET、C#、WPFの話題が多いです。

人気の投稿 / 新着記事

人気記事 新着記事
  • 読み込み中...

ラベル

.NET (5) C# (5) WPF (4)

ブログ アーカイブ

目次

このブログを検索