আমি কীভাবে কোনও স্ট্রিংয়ের মাঝামাঝি থেকে সংস্কৃতি-সংবেদনশীল "শুরু-সহ" অপারেশন করতে পারি?


106

আমার একটি চাহিদা রয়েছে যা তুলনামূলকভাবে অস্পষ্ট, তবে এটি অনুভব করে যে এটি ছাত্রলীগ ব্যবহার করে সম্ভব হওয়া উচিত be

প্রসঙ্গে, আমি নোদা সময়ের একটি তারিখ / সময়ের স্ট্রিং পার্স করছি । আমি ইনপুট স্ট্রিংয়ের মধ্যে আমার অবস্থানের জন্য একটি লজিকাল কার্সার বজায় রাখি। সুতরাং সম্পূর্ণ স্ট্রিং "3 জানুয়ারী 2013" হওয়ার পরে লজিক্যাল কার্সারটি 'জে' তে থাকতে পারে।

এখন, আমাকে সংস্কৃতির জন্য সমস্ত পরিচিত মাসের নামের সাথে তুলনা করে, মাসের নামটি পার্স করা দরকার:

  • সংস্কৃতি-সংবেদনশীলভাবে
  • কেস-insensitively
  • কার্সারের বিন্দু থেকে (পরে নয়; আমি দেখতে চাই যে কার্সারটি প্রার্থীর মাসের নামটি "দেখছে" কিনা)
  • দ্রুত
  • ... এবং পরে আমার জানতে হবে কতগুলি অক্ষর ব্যবহৃত হয়েছিল

এটি করার জন্য বর্তমান কোডটি সাধারণত ব্যবহার করে কাজ করে CompareInfo.Compare। এটি কার্যকরভাবে এর মতো (কেবল মিলের অংশের জন্য - আসল জিনিসটিতে আরও কোড রয়েছে, তবে এটি ম্যাচের সাথে প্রাসঙ্গিক নয়):

internal bool MatchCaseInsensitive(string candidate, CompareInfo compareInfo)
{
    return compareInfo.Compare(text, position, candidate.Length,
                               candidate, 0, candidate.Length, 
                               CompareOptions.IgnoreCase) == 0;
}

তবে এটি প্রার্থী এবং সেই অঞ্চলের উপর নির্ভর করে যা আমরা একই দৈর্ঘ্যের সাথে তুলনা করি। বেশিরভাগ সময় ভাল, তবে কিছু বিশেষ ক্ষেত্রে জরিমানা হয় না । মনে করুন আমাদের মতো কিছু রয়েছে:

// U+00E9 is a single code point for e-acute
var text = "x b\u00e9d y";
int position = 2;
// e followed by U+0301 still means e-acute, but from two code points
var candidate = "be\u0301d";

এখন আমার তুলনা ব্যর্থ হবে। আমি ব্যবহার করতে পারি IsPrefix:

if (compareInfo.IsPrefix(text.Substring(position), candidate,
                         CompareOptions.IgnoreCase))

কিন্তু:

  • এর জন্য আমার একটি সাবস্ট্রিং তৈরি করা দরকার, যা আমি সত্যিই বরং এড়াতে পারি। (আমি নোডা টাইমকে কার্যকরভাবে একটি সিস্টেম লাইব্রেরি হিসাবে দেখছি; পার্সিং পারফরম্যান্স কিছু ক্লায়েন্টের পক্ষে গুরুত্বপূর্ণ হতে পারে))
  • কার্সার পরে কতদূর এগিয়ে যেতে হবে তা আমাকে জানায় না

বাস্তবে, আমি দৃ strongly়ভাবে সন্দেহ করি এটি খুব ঘন ঘন আসবে না ... তবে আমি এখানে সঠিক জিনিসটি করতে চাই । আমি নিজেও ইউনিকোড বিশেষজ্ঞ না হয়ে নিজে নিজে প্রয়োগ না করে এটি করতে সক্ষম হতে চাই :)

( নোডা সময় বাগ 210 হিসাবে উত্থাপিত , কেউ যদি কোনও পরিণতিতে অনুসরণ করতে চায় সে ক্ষেত্রে।)

আমি স্বাভাবিককরণের ধারণাটি পছন্দ করি। ক) নির্ভুলতা এবং খ) পারফরম্যান্সের জন্য আমাকে বিশদটি এটি পরীক্ষা করা দরকার। ধরে নিচ্ছি যে আমি এটিকে সঠিকভাবে কাজ করতে পারি, আমি এখনও নিশ্চিত নই যে এটি কীভাবে সকলের পরিবর্তনের পক্ষে মূল্যবান হবে - এটি এমন এক ধরণের জিনিস যা সম্ভবত বাস্তবে বাস্তবে আসবে না , তবে আমার সমস্ত ব্যবহারকারীর অভিনয়কে আঘাত করতে পারে: (

আমি বিসিএলও পরীক্ষা করে দেখেছি - যা এটি সঠিকভাবে পরিচালনা করতে পারে না। কোডের উদাহরণ:

using System;
using System.Globalization;

class Test
{
    static void Main()
    {
        var culture = (CultureInfo) CultureInfo.InvariantCulture.Clone();
        var months = culture.DateTimeFormat.AbbreviatedMonthNames;
        months[10] = "be\u0301d";
        culture.DateTimeFormat.AbbreviatedMonthNames = months;

        var text = "25 b\u00e9d 2013";
        var pattern = "dd MMM yyyy";
        DateTime result;
        if (DateTime.TryParseExact(text, pattern, culture,
                                   DateTimeStyles.None, out result))
        {
            Console.WriteLine("Parsed! Result={0}", result);
        }
        else
        {
            Console.WriteLine("Didn't parse");
        }
    }
}

"বিএড" এর পাঠ্য মানের সাথে কাস্টম মাসের নামটি "বিছানায়" পরিবর্তন করা হয়েছে জরিমানা।

ঠিক আছে, আরও কয়েকটি তথ্য পয়েন্ট:

  • ব্যবহারের খরচ Substringএবং IsPrefixউল্লেখযোগ্য কিন্তু ভয়ঙ্কর নয়। আমার বিকাশের ল্যাপটপে "শুক্রবার 12 এপ্রিল 2013 20:28:42" এর একটি নমুনায়, এটি আমি প্রায় 460K থেকে প্রায় 460K তে এক সেকেন্ডে সম্পাদন করতে পার্স অপারেশনগুলির সংখ্যা পরিবর্তন করে changes আমি যদি সম্ভব হয় তবে এই মন্দাটি এড়াতে চাই, তবে এটি খুব খারাপ নয়।

  • সাধারণীকরণটি আমার যা ভাবা হয়েছিল তার চেয়ে কম সম্ভব - কারণ এটি পোর্টেবল ক্লাস লাইব্রেরিতে নেই। আমি সম্ভবত এটি কেবল নন-পিসিএল বিল্ডগুলির জন্য ব্যবহার করতে পারলাম , পিসিএল বিল্ডগুলি একটু কম সঠিক হতে দেয়। ( string.IsNormalized) সাধারণকরণের জন্য পরীক্ষার হিট কার্যকারিতাটি প্রতি সেকেন্ডে প্রায় 445K কলে নিয়ে যায়, যা আমি বেঁচে থাকতে পারি। আমি এখনও নিশ্চিত নই যে এটি আমার যা যা করা দরকার তা করে তোলে - উদাহরণস্বরূপ, "ß" যুক্ত এক মাসের নাম অনেক সংস্কৃতিতে "এসএস" এর সাথে মেলে, আমি বিশ্বাস করি ... এবং সাধারণীকরণ এটি করে না।


যদিও আমি স্ট্রিংং তৈরির পারফরম্যান্সের আঘাত এড়াতে আপনার আকাঙ্ক্ষাকে বুঝতে পেরেছি, তবে এটি করা ভাল হতে পারে তবে এর আগে গেমটিতে একটি নির্বাচিত ইউনিকোড নরমালাইজেশন ফর্ম প্রথম দিকে ফিরিয়ে এবং তারপরে আপনি "পয়েন্ট-বাই-পয়েন্ট" হাঁটতে পারবেন জেনে "। সম্ভবত ডি-ফর্ম।
আইডিপোজেবল

@ অনির্বচনীয়: হ্যাঁ, আমি সে সম্পর্কে অবাক হয়েছি। স্পষ্টতই আমি নিজের নাম আগে থেকেই মাসিক করতে পারি। কমপক্ষে আমি একবারে স্বাভাবিকীকরণটি করতে পারি। আমি আশ্চর্য হয়েছি যে স্বাভাবিককরণ পদ্ধতিটি প্রথমে কিছু করা দরকার কিনা তা পরীক্ষা করে দেখুন। আমার স্বাভাবিককরণের তেমন অভিজ্ঞতা নেই - অবশ্যই দেখার একটি উপায় venue
জন স্কিটি

1
যদি আপনার textখুব দীর্ঘ না হয়, আপনি করতে পারেন if (compareInfo.IndexOf(text, candidate, position, options) == position)msdn.microsoft.com/en-us/library/ms143031.aspx তবে যদি textএটি দীর্ঘ হয় তবে এটি যেখানে প্রয়োজন তার বাইরে অনুসন্ধান করতে অনেক সময় নষ্ট করবে।
জিম মিশেল

1
এই সময়েString ক্লাসটি ব্যবহার করে কেবল বাইপাস করুন এবং সরাসরি ব্যবহার করুন । আপনি আরও কোড লেখার শেষ করবেন, তবে আপনি যখন উচ্চ পারফরম্যান্স চান তখনই তা ঘটে ... বা হতে পারে আপনার সি ++ / সিএলআই ;-) এ প্রোগ্রামিং করা উচিতChar[]
ইন্ট্রিপিডিস

1
হবে CompareOptions.IgnoreNonSpace স্বয়ংক্রিয়ভাবেই আপনার আপনার জন্য এই যত্ন নিতে? এটা আমার কাছে (docco থেকে এই আইপ্যাড দুঃখিত! থেকে পরীক্ষা করার জন্য একটি অবস্থান নেই) দেখায় যেন এই একটি (হতে পারে ?) যে বিকল্পের জন্য ব্যবহার-কেস। " ইঙ্গিত করে যে স্ট্রিং তুলনা অবশ্যই ডায়াক্রিটিক্সের মতো সংমিশ্রণকারী অক্ষরগুলিকে অগ্রাহ্য করবে " "
সেপ্টেম্বর

উত্তর:


41

আমি প্রথম </> এক / বহু কেস ম্যাপিংয়ের সমস্যাটি প্রথমে এবং আলাদাভাবে বিভিন্ন নরমালাইজেশন ফর্ম পরিচালনা করা থেকে বিবেচনা করব।

উদাহরণ স্বরূপ:

x heiße y
  ^--- cursor

মেলে heisseকিন্তু তারপরে কার্সার 1টিকে খুব বেশি করে নিয়ে যায়। এবং:

x heisse y
  ^--- cursor

মেলে heißeতবে তারপরে কার্সার 1টিকে খুব কম সরিয়ে নেওয়া হয়।

এটি এমন কোনও চরিত্রের জন্য প্রযোজ্য যেখানে সাধারণ এক থেকে এক ম্যাপিং নেই।

আপনাকে আসলে যে স্ট্রিংয়ের সাথে মিলেছে তার দৈর্ঘ্যটি জানতে হবে। কিন্তু Compare, IndexOf..এটি তথ্য ফেলে দিন। এটা তোলে রেগুলার এক্সপ্রেশনের সাথে সম্ভব হতে পারে কিন্তু বাস্তবায়ন পূর্ণ ক্ষেত্রে ভাঁজ করে না এবং তাই মিলছে না ßকরতে ss/SSযদিও কেস-অবশ মোডে .Compareএবং .IndexOfনা। এবং যাইহোক যাইহোক প্রতিটি প্রার্থীর জন্য নতুন রেজিেক্সগুলি তৈরি করা ব্যয়বহুল হবে।

এর সহজ সমাধান হ'ল অভ্যন্তরীণভাবে কেবল ভাঁজযুক্ত ফর্মগুলিতে স্ট্রিংগুলি সঞ্চয় করা এবং কেস ভাঁজ প্রার্থীদের সাথে বাইনারি তুলনা করা। তারপরে আপনি কার্সারটি সঠিকভাবে স্থানান্তর করতে পারেন .Lengthযেহেতু কার্সারটি অভ্যন্তরীণ উপস্থাপনার জন্য। আপনি হারিয়ে যাওয়া পারফরম্যান্সের বেশিরভাগটি ব্যবহার না করে ফিরে পেতে পারেন CompareOptions.IgnoreCase

দুর্ভাগ্যক্রমে কোনও কেস ফোল্ড ফাংশন অন্তর্নির্মিত নেই এবং দরিদ্র লোকের কেস ফোল্ডিং কাজ করে না কারণ কোনও পূর্ণ কেস ম্যাপিং নেই - ToUpperপদ্ধতিটি ßরূপান্তরিত হয় না SS

উদাহরণস্বরূপ এটি জাভাতে (এবং এমনকি জাভাস্ক্রিপ্টেও) কাজ করে, প্রদত্ত স্ট্রিং যা সাধারণ ফর্ম সি তে থাকে:

//Poor man's case folding.
//There are some edge cases where this doesn't work
public static String toCaseFold( String input, Locale cultureInfo ) {
    return input.toUpperCase(cultureInfo).toLowerCase(cultureInfo);
}

মজার বিষয় মনে রাখবেন যে জাভা উপেক্ষা করা কেস তুলনা সি # এর মতো পুরো ক্ষেত্রে ফোল্ডিং করে না CompareOptions.IgnoreCase। সুতরাং তারা এই বিষয়ে বিপরীত: জাভা পুরো কেসম্যাপিং করে তবে সাধারণ কেস ফোল্ডিং - সি # সহজ কেসমেপিং করে তবে পুরো কেস ভাঁজ করে।

সুতরাং সম্ভবত আপনার স্ট্রিংগুলি ব্যবহার করার আগে ভাঁজগুলি কেটে ফেলার জন্য আপনার কোনও তৃতীয় পক্ষের গ্রন্থাগার প্রয়োজন।


কিছু করার আগে আপনার অবশ্যই নিশ্চিত হতে হবে যে আপনার স্ট্রিংগুলি স্বাভাবিক আকারে রয়েছে আপনি ল্যাটিন স্ক্রিপ্টের জন্য অনুকূলিত এই প্রাথমিক চেক ব্যবহার করতে পারেন:

public static bool MaybeRequiresNormalizationToFormC(string input)
{
    if( input == null ) throw new ArgumentNullException("input");

    int len = input.Length;
    for (int i = 0; i < len; ++i)
    {
        if (input[i] > 0x2FF)
        {
            return true;
        }
    }

    return false;
}

এটি মিথ্যা পজিটিভ দেয় তবে মিথ্যা নেগেটিভ দেয় না, লাতিন স্ক্রিপ্টের অক্ষরগুলি ব্যবহার করার সময় এটি প্রতিটি স্ট্রিংয়ে সম্পাদন করা দরকার হলেও এটি 460 কে পার্স / গুলি মোটেও কমিয়ে দেবে বলে আমি আশা করি না। একটি মিথ্যা ইতিবাচক সাহায্যে আপনি IsNormalizedএকটি সত্য নেতিবাচক / ইতিবাচক পেতে ব্যবহার করতে পারেন এবং তার পরে প্রয়োজনীয় প্রয়োজন হলে স্বাভাবিক করুন।


সুতরাং উপসংহারে, প্রসেসিং হ'ল প্রথমে স্বাভাবিক ফর্ম সি, তারপরে কেস ভাঁজ নিশ্চিত করা। প্রক্রিয়াজাত স্ট্রিংগুলির সাথে বাইনারি তুলনা করুন এবং কার্সারটি সরানোর সাথে সাথে আপনি বর্তমানে এটি চালাচ্ছেন।


এর জন্য ধন্যবাদ - আমাকে আরও বিস্তারিতভাবে সাধারণীকরণ ফর্মটি সন্ধান করতে হবে, তবে এগুলি দুর্দান্ত পয়েন্টার। আমি মনে করি আমি "এটি পিসিএল এর অধীনে সঠিকভাবে কাজ করে না" (যা সাধারণীকরণ সরবরাহ করে না) এর সাথে বেঁচে থাকতে পারি। কেস-ফোল্ডিংয়ের জন্য তৃতীয় পক্ষের লাইব্রেরিটি ব্যবহার করা এখানে অতিমাত্রায় আপত্তিজনক হবে - বর্তমানে আমাদের কোনও তৃতীয় পক্ষের নির্ভরতা নেই, এবং এমন একটি কর্নার কেসের জন্য একটি পরিচয় করিয়ে দিচ্ছি যা এমনকি বিসিএল হ্যান্ডেল করে না এমন ব্যথা হতে পারে। সম্ভবত কেস-ভাঁজ সংস্কৃতি সংবেদনশীল, বিটিডাব্লু (যেমন তুর্কি)?
জন স্কিটি

2
@ জোনস্কিট হ্যাঁ, তুর্কি কেসফোল্ড ম্যাপিংগুলিতে তার নিজস্ব মোডের প্রাপ্য: পি কেসফোল্ডিং.টেক্সট
এসাইলিজা

এই উত্তরের একটি মৌলিক ত্রুটি রয়েছে বলে মনে হয়, এর মধ্যে কেবল কেস-ফোল্ডিংয়ের সময় অক্ষরগুলির মানচিত্রটি লিগচারগুলিতে (এবং তদ্বিপরীতভাবে) বোঝায়। এই ক্ষেত্রে না হয়; এমন লিগচার রয়েছে যা কেসিং নির্বিশেষে অক্ষরের সমান হিসাবে বিবেচিত হয়। উদাহরণস্বরূপ, এন-মার্কিন সংস্কৃতির অধীনে, æসমান aeএবং সমান ffi। সি-নরমালাইজেশন লিগাচারগুলি একেবারেই হ্যান্ডেল করে না, কারণ এটি কেবল সামঞ্জস্যের ম্যাপিংকে (যা সাধারণত অক্ষরের সংমিশ্রণে সীমাবদ্ধ থাকে) মঞ্জুরি দেয়।
ডগলাস

কেসি- এবং কেডি-নরমালাইজেশন কিছু লিগাচার যেমন পরিচালনা করে তবে অন্যকে মিস করে, যেমন æ। সংস্কৃতিগুলির মধ্যে বিভেদগুলির দ্বারা ইস্যুটি আরও খারাপ করা হয়েছে - এন-ইউএস-এর অধীনে æসমান ae, তবে ড-ডি-এর অধীনে নয় , যেমন স্ট্রিংয়ের জন্য এমএসডিএন ডকুমেন্টেশনের অধীনে আলোচিত । সুতরাং, সাধারণকরণ (যে কোনও রূপে) এবং কেস-ম্যাপিং এই সমস্যার যথেষ্ট সমাধান নয় for
ডগলাস

আমার আগের মন্তব্যে ছোট সংশোধন: সি-নরমালাইজেশন কেবল ক্যানোনিকাল ম্যাপিংগুলিকে (যেমন অক্ষরগুলির সংমিশ্রণের জন্য) মঞ্জুরি দেয় , সামঞ্জস্যতা ম্যাপিংগুলিকে নয় (যেমন লিগ্যাচারের জন্য)।
ডগলাস

21

এটি প্রয়োজনীয়তা পূরণ করে কিনা দেখুন ..:

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শুধুমাত্র একবার দিয়ে sourceশুরু সম্পাদন prefix; যদি তা না হয়, তবে IsPrefixফিরে আসে -1; অন্যথায়, ব্যবহৃত অক্ষরের দৈর্ঘ্য source

যাইহোক, আমি বৃদ্ধি ব্যতীত কোন ধারণা আছে length2দ্বারা 1নিম্নলিখিত ক্ষেত্রে:

var candidate="ßssß\u00E9\u0302";
var text="abcd ssßss\u0065\u0301\u0302sss";

var count=
    culture.CompareInfo.IsPrefix(text, candidate, 5, CompareOptions.IgnoreCase);

আপডেট :

আমি কিছুটা পারফ উন্নত করার চেষ্টা করেছি, তবে নিম্নলিখিত কোডটিতে বাগ আছে কিনা তা প্রমাণিত হয়নি:

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;
    }
}

আমি নির্দিষ্ট কেসটি দিয়ে পরীক্ষা করেছি এবং তুলনা প্রায় 3 এ।


আমি সত্যিই বরং এই মত লুপ করতে হবে না। স্বীকার করা যায় খুব শীঘ্রই এটির কিছু পাওয়া গেলে এটি লুপ করা দরকার তবে উদাহরণস্বরূপ "ফেব্রুয়ারী" এর সাথে ম্যাচ করার জন্য আমি 8 স্ট্রিংয়ের তুলনা করতে চাই না। এটির মতো আরও ভাল উপায় থাকতে হবে বলে মনে হয়। এছাড়াও, প্রাথমিক IndexOfঅপারেশনটিকে প্রারম্ভিক অবস্থান থেকে পুরো স্ট্রিংটি দেখতে হবে, যা ইনপুট স্ট্রিং দীর্ঘ হলে পারফরম্যান্সে ব্যথা হবে।
জন স্কিটি

@ জোনস্কিট: আপনাকে ধন্যবাদ লুপটি হ্রাস করা যায় কিনা তা সনাক্ত করতে কিছু যুক্ত করা যেতে পারে। আমি এটি সম্পর্কে চিন্তা করব।
কেন কিন

@ জোনস্কিট: আপনি কি প্রতিবিম্ব ব্যবহার করতে বিবেচনা করবেন? যেহেতু আমি পদ্ধতিগুলিতে সন্ধান করেছি, সেগুলি খুব বেশি দূরে নেটিভ পদ্ধতিতে অনুরোধ জানায়।
কেন কিন

3
প্রকৃতপক্ষে. নোডা টাইম ইউনিকোডের
বিশদটির

2
আমি এই জাতীয় সমস্যাটি একবারে সমাধান করেছি (এইচটিএমএলে অনুসন্ধানের স্ট্রিং হাইলাইট করা)। আমি এটি একইভাবে করেছি। আপনি লুপটি এবং অনুসন্ধান কৌশলটি এমনভাবে সুর করতে পারেন যা সম্ভাব্য কেসগুলি প্রথমে পরীক্ষা করে এটি খুব দ্রুত সম্পন্ন করে। এ সম্পর্কে দুর্দান্ত বিষয়টি হ'ল এটি সম্পূর্ণ সঠিক বলে মনে হচ্ছে এবং ইউনিকোডের কোনও বিবরণ আপনার কোডে ফাঁস হবে না।
usr ডিরেক্টরির

9

এটি স্বাভাবিককরণ এবং ব্যবহার না করেই সম্ভব IsPrefix

আমাদের একই সংখ্যার পাঠ্য উপাদানগুলির একই সংখ্যার অক্ষরের বিপরীতে তুলনা করতে হবে , তবে এখনও মিলে যাওয়া অক্ষরের সংখ্যাটি ফিরিয়ে আনতে হবে।

আমি নোডা সময়ের মধ্যে ভ্যালু কার্সার.সি.এসMatchCaseInsensitive থেকে পদ্ধতির একটি অনুলিপি তৈরি করেছি এবং এটিকে কিছুটা সংশোধন করেছি যাতে এটি একটি স্থির প্রসঙ্গে ব্যবহার করা যায়:

// Noda time code from MatchCaseInsensitive in ValueCursor.cs
static int IsMatch_Original(string source, int index, string match, CompareInfo compareInfo)
{
    unchecked
    {
        if (match.Length > source.Length - index)
        {
            return 0;
        }

        // TODO(V1.2): This will fail if the length in the input string is different to the length in the
        // match string for culture-specific reasons. It's not clear how to handle that...
        if (compareInfo.Compare(source, index, match.Length, match, 0, match.Length, CompareOptions.IgnoreCase) == 0)
        {
            return match.Length;
        }

        return 0;
    }
}

(কেবলমাত্র রেফারেন্সের জন্য অন্তর্ভুক্ত করা হয়েছে, এটি এমন কোড যা আপনার জানা হিসাবে সঠিকভাবে তুলনা করবে না)

এই পদ্ধতির নীচের রূপটি স্ট্রিংইনফো.গেটনেক্সটেক্সটেলমেন্ট ব্যবহার করে যা ফ্রেমওয়ার্ক সরবরাহ করে। একটি মিল খুঁজে পেতে পাঠ্য উপাদানটির সাথে পাঠ্যের উপাদানটির তুলনা করা ধারণাটি পাওয়া যায় এবং যদি পাওয়া যায় তবে উত্সের স্ট্রিংয়ের সাথে মিলের অক্ষরের প্রকৃত সংখ্যাটি পাওয়া যায়:

// Using StringInfo.GetNextTextElement to match by text elements instead of characters
static int IsMatch_New(string source, int index, string match, CompareInfo compareInfo)
{
    int sourceIndex = index;
    int matchIndex = 0;

    // Loop until we reach the end of source or match
    while (sourceIndex < source.Length && matchIndex < match.Length)
    {
        // Get text elements at the current positions of source and match
        // Normally that will be just one character but may be more in case of Unicode combining characters
        string sourceElem = StringInfo.GetNextTextElement(source, sourceIndex);
        string matchElem = StringInfo.GetNextTextElement(match, matchIndex);

        // Compare the current elements.
        if (compareInfo.Compare(sourceElem, matchElem, CompareOptions.IgnoreCase) != 0)
        {
            return 0; // No match
        }

        // Advance in source and match (by number of characters)
        sourceIndex += sourceElem.Length;
        matchIndex += matchElem.Length;
    }

    // Check if we reached end of source and not end of match
    if (matchIndex != match.Length)
    {
        return 0; // No match
    }

    // Found match. Return number of matching characters from source.
    return sourceIndex - index;
}

অন্ততপক্ষে আমার পরীক্ষার কেস অনুসারে এই পদ্ধতিটি ঠিক কাজ করে (যা মূলত কেবলমাত্র আপনার সরবরাহ করা স্ট্রিংয়ের কয়েকটি বৈকল্পিক পরীক্ষা করে: "b\u00e9d"এবং "be\u0301d")।

তবে, getNextTextElement পদ্ধতিতে প্রতিটি পাঠ্য উপাদানগুলির জন্য একটি স্ট্রিং তৈরি করে তাই এই প্রয়োগের জন্য প্রচুর পরিমাণে স্ট্রিং তুলনা প্রয়োজন - যা কার্য সম্পাদনে প্রভাব ফেলবে।

সুতরাং, আমি আরও একটি বৈকল্পিক তৈরি করেছি যা GetNextTextElement ব্যবহার করে না বরং পরিবর্তে অক্ষরগুলিতে প্রকৃত মিলের দৈর্ঘ্য সন্ধান করতে ইউনিকোডের অক্ষরগুলির সংমিশ্রণটি ছাড়বে :

// This should be faster
static int IsMatch_Faster(string source, int index, string match, CompareInfo compareInfo)
{
    int sourceLength = source.Length;
    int matchLength = match.Length;
    int sourceIndex = index;
    int matchIndex = 0;

    // Loop until we reach the end of source or match
    while (sourceIndex < sourceLength && matchIndex < matchLength)
    {
        sourceIndex += GetTextElemLen(source, sourceIndex, sourceLength);
        matchIndex += GetTextElemLen(match, matchIndex, matchLength);
    }

    // Check if we reached end of source and not end of match
    if (matchIndex != matchLength)
    {
        return 0; // No match
    }

    // Check if we've found a match
    if (compareInfo.Compare(source, index, sourceIndex - index, match, 0, matchIndex, CompareOptions.IgnoreCase) != 0)
    {
        return 0; // No match
    }

    // Found match. Return number of matching characters from source.
    return sourceIndex - index;
}

এই পদ্ধতিতে নিম্নলিখিত দুটি সহায়ক ব্যবহার করা হয়:

static int GetTextElemLen(string str, int index, int strLen)
{
    bool stop = false;
    int elemLen;

    for (elemLen = 0; index < strLen && !stop; ++elemLen, ++index)
    {
        stop = !IsCombiningCharacter(str, index);
    }

    return elemLen;
}

static bool IsCombiningCharacter(string str, int index)
{
    switch (CharUnicodeInfo.GetUnicodeCategory(str, index))
    {
        case UnicodeCategory.NonSpacingMark:
        case UnicodeCategory.SpacingCombiningMark:
        case UnicodeCategory.EnclosingMark:
            return true;

        default:
            return false;
    }
}

আমি কোনও বেঞ্চ চিহ্নিতকরণ করিনি, তাই দ্রুত পদ্ধতিটি আসলে দ্রুততর কিনা তা সত্যই আমি জানি না। বা আমি কোনও বর্ধিত পরীক্ষাও করিনি।

তবে ইউনিকোডের সমন্বয়যুক্ত অক্ষরগুলির মধ্যে স্ট্রিংগুলির জন্য কীভাবে সাংস্কৃতিক সংবেদনশীল সাবস্ট্রিং মেলানো যায় তা আপনার প্রশ্নের উত্তর দেওয়া উচিত।

এগুলি আমি পরীক্ষার কেসগুলি ব্যবহার করেছি:

static Tuple<string, int, string, int>[] tests = new []
{
    Tuple.Create("x b\u00e9d y", 2, "be\u0301d", 3),
    Tuple.Create("x be\u0301d y", 2, "b\u00e9d", 4),

    Tuple.Create("x b\u00e9d", 2, "be\u0301d", 3),
    Tuple.Create("x be\u0301d", 2, "b\u00e9d", 4),

    Tuple.Create("b\u00e9d y", 0, "be\u0301d", 3),
    Tuple.Create("be\u0301d y", 0, "b\u00e9d", 4),

    Tuple.Create("b\u00e9d", 0, "be\u0301d", 3),
    Tuple.Create("be\u0301d", 0, "b\u00e9d", 4),

    Tuple.Create("b\u00e9", 0, "be\u0301d", 0),
    Tuple.Create("be\u0301", 0, "b\u00e9d", 0),
};

প্রধান মানসমূহ হ'ল:

  1. উত্সের স্ট্রিং (খড়ের গালি)
  2. উত্স সূচনা অবস্থান।
  3. ম্যাচের স্ট্রিং (সুই)।
  4. প্রত্যাশিত ম্যাচের দৈর্ঘ্য।

তিনটি পদ্ধতিতে এই পরীক্ষাগুলি চালানোর ফলে ফলাফল পাওয়া যায়:

Test #0: Orignal=BAD; New=OK; Faster=OK
Test #1: Orignal=BAD; New=OK; Faster=OK
Test #2: Orignal=BAD; New=OK; Faster=OK
Test #3: Orignal=BAD; New=OK; Faster=OK
Test #4: Orignal=BAD; New=OK; Faster=OK
Test #5: Orignal=BAD; New=OK; Faster=OK
Test #6: Orignal=BAD; New=OK; Faster=OK
Test #7: Orignal=BAD; New=OK; Faster=OK
Test #8: Orignal=OK; New=OK; Faster=OK
Test #9: Orignal=OK; New=OK; Faster=OK

সোর্স স্ট্রিং ম্যাচের স্ট্রিংয়ের চেয়ে সংক্ষিপ্ত যখন শেষ দুটি পরীক্ষাগুলি কেসটি পরীক্ষা করে। এক্ষেত্রে মূল (নোডা সময়) পদ্ধতিটিও সফল হবে।


এই জন্য আপনাকে অনেক ধন্যবাদ. এটি কতটা ভাল পারফর্ম করে তা দেখতে আমার এটিকে বিশদভাবে দেখতে হবে তবে এটি দেখতে দুর্দান্ত পয়েন্ট হিসাবে দেখায় looks ইউনিকোড সম্পর্কে আরও জ্ঞান (কোডের মধ্যেই) প্রয়োজন হতে পারে বলে আমি আশা করি , তবে প্ল্যাটফর্মটি যা প্রয়োজন তা না করে, আমি সে সম্পর্কে অনেক কিছুই করতে পারি না :(
জোন স্কিটে

@ জোনস্কিট: যে কোনও সাহায্যের জন্য খুশি! এবং হ্যাঁ, ইউনিকোড সমর্থনের সাথে মেলানো স্ট্রিংগুলি অবশ্যই অবশ্যই কাঠামোর মধ্যে অন্তর্ভুক্ত করা উচিত ...
মর্টেন উইকস্ট্রম
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.