How can I perform a culture-sensitive “starts-with” operation from the middle of a string?

前端 未结 3 1625
长情又很酷
长情又很酷 2020-12-28 11:12

I have a requirement which is relatively obscure, but it feels like it should be possible using the BCL.

For context, I\'m parsing a date/time string in Nod

3条回答
  •  -上瘾入骨i
    2020-12-28 11:51

    See if this meets the requirement .. :

    public static partial class GlobalizationExtensions {
        public static int IsPrefix(
            this CompareInfo compareInfo,
            String source, String prefix, int startIndex, CompareOptions options
            ) {
            if(compareInfo.IndexOf(source, prefix, startIndex, options)!=startIndex)
                return ~0;
            else
                // source is started with prefix
                // therefore the loop must exit
                for(int length2=0, length1=prefix.Length; ; )
                    if(0==compareInfo.Compare(
                            prefix, 0, length1, 
                            source, startIndex, ++length2, options))
                        return length2;
        }
    }
    

    compareInfo.Compare only performs once source started with prefix; if it didn't, then IsPrefix returns -1; otherwise, the length of characters used in source.

    However, I have no idea except increment length2 by 1 with the following case:

    var candidate="ßssß\u00E9\u0302";
    var text="abcd ssßss\u0065\u0301\u0302sss";
    
    var count=
        culture.CompareInfo.IsPrefix(text, candidate, 5, CompareOptions.IgnoreCase);
    

    update:

    I tried to improve a little bit of perf., but it isn't proved whether there's bug in the following code:

    public static partial class GlobalizationExtensions {
        public static int Compare(
            this CompareInfo compareInfo,
            String source, String prefix, int startIndex, ref int length2, 
            CompareOptions options) {
            int length1=prefix.Length, v2, v1;
    
            if(0==(v1=compareInfo.Compare(
                prefix, 0, length1, source, startIndex, length2, options))
                ) {
                return 0;
            }
            else {
                if(0==(v2=compareInfo.Compare(
                    prefix, 0, length1, source, startIndex, 1+length2, options))
                    ) {
                    ++length2;
                    return 0;
                }
                else {
                    if(v1<0||v2<0) {
                        length2-=2;
                        return -1;
                    }
                    else {
                        length2+=2;
                        return 1;
                    }
                }
            }
        }
    
        public static int IsPrefix(
            this CompareInfo compareInfo,
            String source, String prefix, int startIndex, CompareOptions options
            ) {
            if(compareInfo.IndexOf(source, prefix, startIndex, options)
                    !=startIndex)
                return ~0;
            else
                for(int length2=
                        Math.Min(prefix.Length, source.Length-(1+startIndex)); ; )
                    if(0==compareInfo.Compare(
                            source, prefix, startIndex, ref length2, options))
                        return length2;
        }
    }
    

    I tested with the particular case, and the comparision down to about 3.

提交回复
热议问题