سؤال

ولدي طريقة لاستبدال كل حرف باستثناء تلك أحدده. على سبيل المثال،

ReplaceNot("test. stop; or, not", ".;/\\".ToCharArray(), '*'); 

وسيعود

"****.*****;***,****".

والآن، وهذا ليس مثيل التحسين سابق لأوانه. I استدعاء هذا الأسلوب مرات قليلة جدا خلال عملية الشبكة. لقد وجدت أن على سلاسل أطول، فإنه يسبب بعض الكمون، وإزالته ساعدت قليلا. أي مساعدة لتسريع هذا الأمر موضع تقدير.

    public static string ReplaceNot(this string original, char[] pattern, char replacement)
    {           
        int index = 0;
        int old = -1;

        StringBuilder sb = new StringBuilder(original.Length);

        while ((index = original.IndexOfAny(pattern, index)) > -1)
        {
            sb.Append(new string(replacement, index - old - 1));
            sb.Append(original[index]);
            old = index++;
        }

        if (original.Length - old > 1)
        {
            sb.Append(new string(replacement, original.Length - (old + 1)));
        }

        return sb.ToString();
    }

ونهائي # الصورة. أود أيضا أن أضيف حالة اختبار لسلسلة أحرف 3K، ركض في 100K مرات بدلا من 1M لمعرفة مدى نجاح كل من هذه المقاييس. وكانت المفاجأة الوحيدة التي التعبير العادي "تحجيم أفضل" من الآخرين، لكنه لا يساعد لأنه بطيء جدا لتبدأ:

User            Short * 1M  Long * 100K     Scale
John            319             2125            6.66
Luke            360             2659            7.39
Guffa           409             2827            6.91
Mine            447             3372            7.54
DirkGently      1094            9134            8.35
Michael         1591            12785           8.04
Peter           21106           94386           4.47

تحديث: أدليت به خلق التعبير العادي لبطرس نسخة متغير ثابت، وتعيينه إلى RegexOptions.Compiled لكي نكون منصفين:

User            Short * 1M      Long * 100K     Scale
Peter           8997            74715           8.30

وباستبين تصل إلى قانون بلدي الاختبار، يرجى تصحيح لي إذا كان الخطأ:   HTTP: //pastebin.com/f64f260ee

هل كانت مفيدة؟

المحلول

حسنا، على سلسلة ~ 60KB، وهذا سوف تؤدي أسرع حوالي 40٪ من الإصدار الخاص بك:

public static string ReplaceNot(this string original, char[] pattern, char replacement)
{
    int index = 0;

    StringBuilder sb = new StringBuilder(new string(replacement, original.Length));

    while ((index = original.IndexOfAny(pattern, index)) > -1)
    {
        sb[index] = original[index++];
    }

    return sb.ToString();
}

وهو خدعة لتهيئة سلسلة جديدة مع جميع الشخصيات الاستبدال، لأن معظمها سيتم استبدالها.

نصائح أخرى

لا يمكن استخدام Regex.Replace مثل ذلك:

Regex regex = new Regex(@"[^.;/\\]");
string s = regex.Replace("test. stop; or, not", "*");

وأنا لا أعرف إذا كان هذا سيكون أي أسرع، ولكنه يتجنب newing تصل سلاسل فقط بحيث يمكن إلحاق باني السلسلة، والذي قد يساعد على:

    public static string ReplaceNot(this string original, char[] pattern, char replacement)
    {
        StringBuilder sb = new StringBuilder(original.Length);

        foreach (char ch in original) {
            if (Array.IndexOf( pattern, ch) >= 0) {
                sb.Append( ch);
            }
            else {
                sb.Append( replacement);
            }
        }

        return sb.ToString();
    }

وإذا كان عدد حروف في pattern سيكون من أي حجم (التي انا التخمين عموما لن)، قد دفع لترتيب هذا الأمر وإجراء Array.BinarySearch() بدلا من Array.indexOf().

لمثل هذا التحول بسيط، كنت أراهن أنه سيكون لديك أي مشكلة أن تكون أسرع من التعابير المنطقية أيضا.

وأيضا، لأن لديك مجموعة من الشخصيات في pattern من المحتمل أن تأتي عادة من سلسلة على أي حال (على الأقل هذا ما كان تجربتي العامة مع هذا النوع من API)، لماذا لا يكون لديك توقيع الأسلوب يكون:

public static string ReplaceNot(this string original, string pattern, char replacement)

وأو الأفضل من ذلك، لديها الزائد حيث pattern يمكن أن يكون char[] أو string؟

وهنا نسخة أخرى بالنسبة لك. بلدي التجارب تشير إلى أن أدائها جيد جدا.

public static string ReplaceNot(
    this string original, char[] pattern, char replacement)
{
    char[] buffer = new char[original.Length];

    for (int i = 0; i < buffer.Length; i++)
    {
        bool replace = true;

        for (int j = 0; j < pattern.Length; j++)
        {
            if (original[i] == pattern[j])
            {
                replace = false;
                break;
            }
        }

        buffer[i] = replace ? replacement : original[i];
    }

    return new string(buffer);
}

ووب StringBuilder لديه الزائد التي تأخذ طابعا والعد، لذلك لم يكن لديك لإنشاء سلاسل المتوسطة إضافة إلى ب StringBuilder. أحصل على تحسين حوالي 20٪ عن طريق استبدال هذا:

sb.Append(new string(replacement, index - old - 1));

ومع:

sb.Append(replacement, index - old - 1);

وهذا:

sb.Append(new string(replacement, original.Length - (old + 1)));

ومع:

sb.Append(replacement, original.Length - (old + 1));

و(I اختبار التعليمات البرمجية التي قلت كان حوالي أربع مرات أسرع، وأجد أنه من حوالي 15 مرات أبطأ ...)

وانها ستكون O (ن). يبدو أنك استبدال جميع الحروف الهجائية والفراغات التي كتبها *، لماذا لا مجرد اختبار إذا كان الحرف الحالي هو الأبجدية / بيضاء واستبداله؟

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top