确定字符串是否为合法XML元素名称的有效方法

The*_*Dag 2 c# xml algorithm perf

我做了一个符合W3规范的简单实现.在这里,我只是持有不同的合法字符集(合法的起始字符不同于以下字符)并使用string.Contains.但是这些合法字符组合令人惊讶地(对我来说)很大,只是在候选字符串的时候检查一个字符变得有点贵.

目前这不是一个问题,因为我需要每次执行一次(几秒钟,几分钟甚至几小时)验证一些字符串一次(花费几毫秒),但我很想知道其他人会建议什么.

这是我直截了当的实现:

using System;
using System.Text;
using Project.Common; // Guard

namespace Project.Common.XmlUtilities
{
    static public class XmlUtil
    {
        static public bool IsLegalElementName(string localName)
        {
            Guard.ArgumentNotNull(localName, "localName");
            if (localName == "") 
                return false;

            if (NameStartChars.IndexOf(localName[0]) == -1)
                return false;

            for (int i = 1; i < localName.Length; i++)
                if (NameChars.IndexOf(localName[i]) == -1)
                    return false;

            return true;
        }


        // See W3 spec at http://www.w3.org/TR/REC-xml/#NT-NameStartChar.
        static public readonly string NameStartChars = AZ.ToLower() + AZ + ":_" + GetStringFromCharRanges(0xC0, 0xD6, 0xD8, 0xF6, 0xF8, 0x2FF, 0x370, 0x37D, 0x37F, 0x1FFF, 0x200C, 0x200D, 0x2070, 0x218F, 0x2C00, 0x2FEF, 0x3001, 0xD7FF, 0xF900, 0xFDCF, 0xFDF0, 0xFFFD, 0x10000, 0xEFFFF);

        // See W3 spec at http://www.w3.org/TR/REC-xml/#NT-NameChar.
        static public readonly string NameChars = NameStartChars + "-.0123456789" + char.ConvertFromUtf32(0xB7) + GetStringFromCharRanges(0x0300, 0x036F, 0x203F, 0x2040);

        public const string AZ = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";

        // Hacky but convenient: alternating low-high unicode points specifies multiple ranges, e.g. 0-5 and 10-12 would be 0, 5, 10, 12.
        static string GetStringFromCharRanges(params int[] lowHigh)
        {
            var sb = new StringBuilder();
            for (int i = 0; i < lowHigh.Length; i += 2)
            {
                int low = lowHigh[i];
                int high = lowHigh[i + 1];
                for (int ci=low; ci < high; ci++)
                    sb.Append(char.ConvertFromUtf32(ci));
            }
            return sb.ToString();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

虽然我没有打算构建它,但我认为在类型初始化器中创建一个排序列表,并对列表进行二进制搜索(而不是使用string.Contains进行线性搜索)以检查每个字符是否会在空间,时间之间取得良好的平衡和复杂性.但也许你有其他(更好!)的想法?

Hen*_*man 5

存在一个static string VerifyName(string name)函数,但它会为无效名称抛出异常.

我还是喜欢用这个:

try
{
    XmlConvert.VerifyName(name);
    return true;
}
catch
{
   return false;
}
Run Code Online (Sandbox Code Playgroud)

  • 将此标记为答案,尽管我希望Microsoft将逻辑暴露为简单返回bool的方法(也许是XmlElement.IsLegalName).像我们得到的虚拟异常抛出变体将是一个方便的补充,但我不确定XmlConvert是托管逻辑的最合乎逻辑的类.:) (3认同)