java.util.regex - Pattern.compile এর গুরুত্ব ()?


118

Pattern.compile()পদ্ধতির গুরুত্ব কী ? অবজেক্টটি
পাওয়ার আগে আমাকে কেন রেজেক্স স্ট্রিং সংকলন করতে হবে Matcher?

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

String regex = "((\\S+)\\s*some\\s*";

Pattern pattern = Pattern.compile(regex); // why do I need to compile
Matcher matcher = pattern.matcher(text);

2
ঠিক আছে, বাস্তবায়ন (জেডিকে ১.7-এর মতো) নতুন প্যাটার্নের (কেবলমাত্র, ০) কেবলমাত্র শর্টকাট হলে গুরুত্বটি প্রায় নেই E এটি বলেছিল, বাস্তব গুরুত্ব স্ট্যাটিক পদ্ধতি নিজেই নয়, তবে একটি নতুন প্যাটার্ন তৈরি এবং প্রত্যাবর্তন যা পরবর্তী ব্যবহারের জন্য সংরক্ষণ করা যায়। সম্ভবত অন্যান্য বাস্তবায়ন রয়েছে যেখানে স্থিতিশীল পদ্ধতিটি একটি নতুন রুট নিয়ে যায় এবং প্যাটার্ন অবজেক্টগুলিকে ক্যাশে করে এবং এটি প্যাটার্ন ডটকমপিলে () গুরুত্বের প্রকৃত ঘটনা হবে!
মার্কোলপস

উত্তরগুলি পৃথকীকরণের প্যাটার্ন এবং ম্যাচিং ক্লাসগুলির গুরুত্বকে আলোকপাত করে (যা সম্ভবত প্রশ্নটি জিজ্ঞাসা করে) তবে আমরা কেন new Pattern(regex)স্থির সংকলন ফাংশনের পরিবর্তে কেবল নির্মাণকারী ব্যবহার করতে পারি না তা উত্তর দেয় না । মার্কোলোপস মন্তব্য স্পট হয়।
কন সাইক

উত্তর:


144

compile()পদ্ধতি সবসময় কিছু সময়ে বলা হয়; এটি প্যাটার্ন অবজেক্ট তৈরির একমাত্র উপায়। সুতরাং প্রশ্নটি আসলে, আপনি কেন এটি স্পষ্টভাবে কল করবেন ? একটি কারণ হ'ল ম্যাচারের অবজেক্টের জন্য আপনার একটি রেফারেন্স প্রয়োজন যাতে আপনি এর পদ্ধতিগুলি ব্যবহার করতে পারেন, যেমন group(int)ক্যাপচারিং গ্রুপগুলির সামগ্রীগুলি পুনরুদ্ধার করতে। ম্যাচারের অবজেক্টের হোল্ড পাওয়ার একমাত্র উপায় হ'ল প্যাটার্ন অবজেক্টের matcher()পদ্ধতির মাধ্যমে এবং প্যাটার্ন অবজেক্টের আওল্ড পাওয়ার একমাত্র উপায় compile()পদ্ধতিটির মাধ্যমে । তারপরে একটি find()পদ্ধতি রয়েছে যা matches()স্ট্রিং বা প্যাটার্ন ক্লাসে নকল হয় না।

অন্য কারণ হ'ল বারবার একই প্যাটার্ন অবজেক্ট তৈরি করা এড়ানো। আপনি যখনই স্ট্রিংয়ের (অথবা matches()প্যাটার্নে স্থির পদ্ধতি) রেগেক্স-চালিত পদ্ধতিগুলির একটি ব্যবহার করেন , এটি একটি নতুন প্যাটার্ন এবং একটি নতুন ম্যাচার তৈরি করে। সুতরাং এই কোড স্নিপেট:

for (String s : myStringList) {
    if ( s.matches("\\d+") ) {
        doSomething();
    }
}

... এর ঠিক সমান:

for (String s : myStringList) {
    if ( Pattern.compile("\\d+").matcher(s).matches() ) {
        doSomething();
    }
}

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

Pattern p = Pattern.compile("\\d+");
Matcher m = p.matcher("");
for (String s : myStringList) {
    if ( m.reset(s).matches() ) {
        doSomething();
    }
}

আপনি যদি নেট নেটজেজসের সাথে পরিচিত হন, আপনি ভাবতে পারেন যে জাভা compile()পদ্ধতিটি নেট নেটফায়ারটির সাথে সম্পর্কিত কিনা RegexOptions.Compiled; উত্তর না হয়। জাভার Pattern.compile()পদ্ধতিটি কেবল নেট নেট এর রেজেক্স কন্সট্রাক্টরের সমতুল্য। আপনি যখন Compiledবিকল্পটি নির্দিষ্ট করেন :

Regex r = new Regex(@"\d+", RegexOptions.Compiled); 

... এটি রেগেক্সকে সরাসরি সিআইএল বাইট কোডে সংকলন করে, এটি আরও দ্রুত সঞ্চালনের অনুমতি দেয়, তবে আপ-ফ্রন্ট প্রসেসিং এবং মেমরির ব্যবহারের জন্য একটি উল্লেখযোগ্য ব্যয়ে - এটিকে রেজিক্সগুলির স্টেরয়েড হিসাবে ভাবেন। জাভার কোন সমতুল্য নেই; পর্দার পিছনে যে প্যাটার্নটি তৈরি করা হয়েছে String#matches(String)এবং আপনি স্পষ্টভাবে তৈরি করেছেন তার মধ্যে কোনও পার্থক্য নেই Pattern#compile(String)

(সম্পাদনা: আমি প্রাথমিকভাবে বলেছি যে সমস্ত .NET রেইজেক্স অবজেক্ট ক্যাশেড, যা ভুল।। নেট 2.0, যেহেতু স্বয়ংক্রিয় ক্যাচিং কেবল স্থির পদ্ধতিগুলির সাথে ঘটে Regex.Matches()যখন আপনি সরাসরি রেজেক্স কনস্ট্রাক্টরকে কল করেন না ref রেফ )


1
তবুও, এটি প্যাটার্ন ক্লাসে এই জাতীয় ট্র্যাভিল পদ্ধতির গুরুত্ব ব্যাখ্যা করে না! আমি সবসময় ধরেই নিয়েছিলাম যে স্ট্যাটিক পদ্ধতি প্যাটার্ন ডটকম ফাইলটি নতুন প্যাটার্নে সরল শর্টকাট থেকে অনেক বেশি ছিল (রেজেক্স, 0); আমি সংকলিত নিদর্শনগুলির একটি ক্যাচ আশা করছিলাম ... আমি ভুল ছিলাম। নতুন প্যাটার্ন তৈরির চেয়ে ক্যাশে তৈরি করা বেশি ব্যয়বহুল ??
মার্কোলপস

9
দয়া করে মনে রাখবেন ম্যাচার ক্লাস থ্রেড নিরাপদ নয় এবং থ্রেডগুলিতে ভাগ করা উচিত নয়। অন্যদিকে প্যাটার্ন.কম.পাইল ()।
gswierczynski

1
TLDR; "... [প্যাটার্ন.কম.পাইল (...)] সরাসরি সিআইএল বাইট কোডের সাথে রেইগেক্স সংকলন করে, এটি আরও দ্রুত সঞ্চালনের অনুমতি দেয়, তবে আপ-ফ্রন্ট প্রসেসিং এবং মেমরির ব্যবহারে একটি উল্লেখযোগ্য ব্যয়ে"
সীন.বায়ার

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

@ ভলকসম্যান যা সাধারণ পরামর্শ নিরাপদ নয় কারণ ম্যাচারে অবজেক্টগুলি থ্রেডসেফ নয়। এটি প্রশ্নের সাথেও প্রাসঙ্গিক নয়। তবে হ্যাঁ, আপনি resetকোনও ম্যাচার অবজেক্টটি বরাদ্দ হ্রাস করার জন্য একবারে কেবল একটি থ্রেড দ্বারা ব্যবহার করতে পারেন।
অ্যান্ড্রুএফ

40

কম্পাইল parses রেগুলার এক্সপ্রেশন এবং একটি তৈরী করে ইন-মেমোরি উপস্থাপনা । সংকলনের জন্য ওভারহেড একটি ম্যাচের তুলনায় গুরুত্বপূর্ণ। আপনি যদি বারবার কোনও প্যাটার্ন ব্যবহার করেন তবে এটি সংকলিত প্যাটার্নটি ক্যাশে কিছু কার্যকারিতা অর্জন করবে।


7
এছাড়াও আপনি অতিরিক্ত ফ্ল্যাগ প্যারামিটারে পাস করে সংকলনের সময় কেস_সেন্সিটিভ, ডট_এল ইত্যাদির পতাকাগুলি নির্দিষ্ট করতে পারেন
স্যাম

17

যখন আপনি জাভাটি সংকলন করেন তখন দ্রুত Patternম্যাচগুলি সন্ধান করার জন্য কিছু গণনা করেন String। (রেগেক্সের একটি ইন-মেমরি উপস্থাপনা তৈরি করে)

আপনি যদি Patternএকাধিকবার পুনঃব্যবহার করতে যাচ্ছেন তবে Patternপ্রতিবার একটি নতুন তৈরি করার সময় আপনি বিস্তৃত পারফরম্যান্স বৃদ্ধি পাবে ।

কেবলমাত্র প্যাটার্নটি একবার ব্যবহার করার ক্ষেত্রে, সংকলনের পদক্ষেপটি কেবল কোডের একটি অতিরিক্ত রেখার মতো মনে হয়, তবে বাস্তবে এটি সাধারণ ক্ষেত্রে খুব সহায়ক হতে পারে।


5
অবশ্যই আপনি সব এক লাইনে লিখতে পারেন Matcher matched = Pattern.compile(regex).matcher(text);। একটি একক পদ্ধতি প্রবর্তনের ক্ষেত্রে এর সুবিধাগুলি রয়েছে: যুক্তিগুলি কার্যকরভাবে নামকরণ করা হয়েছে এবং এটি Patternআরও কার্যকর পারফরম্যান্সের জন্য কীভাবে কার্যকর করা যায় (বা পদ্ধতিগুলিতে বিভক্ত হওয়া) এটি সুস্পষ্ট ।
টম হাটিন -

1
দেখে মনে হচ্ছে আপনি জাভা সম্পর্কে এত কিছু জানেন। তাদের আপনার জন্য তাদের কাজের জন্য নিয়োগ দেওয়া উচিত ...
jjnguy

5

এটি পারফরম্যান্স এবং মেমরির ব্যবহারের বিষয়, আপনার যদি এটি ব্যবহার করার প্রয়োজন হয় তবে কমপ্লাইড প্যাটার্নটি সংকলন এবং রাখুন। রেগেক্সের একটি সাধারণ ব্যবহার হ'ল ব্যবহারকারীর ইনপুট (ফর্ম্যাট) যাচাই করা হয় এবং ব্যবহারকারীর জন্য আউটপুট ডেটা ফর্ম্যাট করে , এই ক্লাসে, মেনে চলা প্যাটার্নটি সংরক্ষণ করা হয়, কারণ তারা সাধারণত অনেক কিছু বলে।

নীচে একটি নমুনা যাচাইকারী রয়েছে, যা সত্যই অনেক বলা হয় :)

public class AmountValidator {
    //Accept 123 - 123,456 - 123,345.34
    private static final String AMOUNT_REGEX="\\d{1,3}(,\\d{3})*(\\.\\d{1,4})?|\\.\\d{1,4}";
    //Compile and save the pattern  
    private static final Pattern AMOUNT_PATTERN = Pattern.compile(AMOUNT_REGEX);


    public boolean validate(String amount){

         if (!AMOUNT_PATTERN.matcher(amount).matches()) {
            return false;
         }    
        return true;
    }    
}

@ অ্যালান মুর দ্বারা উল্লিখিত হিসাবে, আপনার কোডে যদি পুনরায় ব্যবহারযোগ্য রেইগেক্স থাকে, (উদাহরণস্বরূপ একটি লুপের আগে) আপনাকে পুনরায় ব্যবহারের জন্য প্যাটার্নটি সঙ্কলন করতে হবে এবং সংরক্ষণ করতে হবে।


2

Pattern.compile()একাধিকবার একটি রেজেক্স পুনরায় ব্যবহার করার অনুমতি দিন (এটি থ্রেডসেফ)। পারফরম্যান্স সুবিধা বেশ তাৎপর্যপূর্ণ হতে পারে।

আমি একটি দ্রুত মানদণ্ড করেছি:

    @Test
    public void recompile() {
        var before = Instant.now();
        for (int i = 0; i < 1_000_000; i++) {
            Pattern.compile("ab").matcher("abcde").matches();
        }
        System.out.println("recompile " + Duration.between(before, Instant.now()));
    }

    @Test
    public void compileOnce() {
        var pattern = Pattern.compile("ab");
        var before = Instant.now();
        for (int i = 0; i < 1_000_000; i++) {
            pattern.matcher("abcde").matches();
        }
        System.out.println("compile once " + Duration.between(before, Instant.now()));
    }

কম্পাইলঅনস দ্রুত 3x এবং 4x এর মধ্যে ছিল । আমি অনুমান করি এটি অত্যন্ত রেগেক্সের উপর নির্ভর করে তবে একটি রেইজেক্সের জন্য যা প্রায়শই ব্যবহৃত হয়, আমি এটার জন্য যাইstatic Pattern pattern = Pattern.compile(...)


0

রেগেক্স প্রাক-সংকলন গতি বৃদ্ধি করে। ম্যাচারের পুনরায় ব্যবহার আপনাকে অন্য সামান্য গতিবেগ দেয়। যদি পদ্ধতিটি ঘন ঘন বলা হয় তবে একটি লুপের মধ্যে কল হয়ে যায়, সামগ্রিক পারফর্মেন্স অবশ্যই উপরে চলে যাবে।


0

'প্যাটার্ন.কম.পাইল' এর মতোই এখানে 'রেকম্পিলার.কম' ফাইল রয়েছে [com.sun.org.apache.regexp.intern থেকে] যেখানে:
1. প্যাটার্নের জন্য সংকলিত কোড [এজে ] এতে 'আজ' রয়েছে
2. এর জন্য সংকলিত কোড নিদর্শন [0-9] এর '09' রয়েছে
3. প্যাটার্নের জন্য সংকলিত কোড [এবিসি] এতে 'আববিসিসি' রয়েছে।

সুতরাং সংকলিত কোড একাধিক ক্ষেত্রে সাধারণকরণের দুর্দান্ত উপায়। সুতরাং পরিবর্তে বিভিন্ন কোড হ্যান্ডলিং পরিস্থিতি থাকার পরিবর্তে 1,2 এবং 3। সংকলিত কোডটিতে উপস্থিত এবং পরবর্তী উপাদানগুলির ascii এর সাথে তুলনা করতে সমস্যা হ্রাস পায়, সুতরাং জোড়গুলি। এভাবে
ক। a এবং z এর মধ্যে ascii সহ যেকোনো কিছুই a এবং z
b এর মধ্যে। 'এ এবং' এর মধ্যে অ্যাসিআইয়ের সাথে যে কোনও কিছু অবশ্যই 'ক'


0

প্যাটার্ন ক্লাসটি হ'ল রেজেক্স ইঞ্জিনের প্রবেশ পয়েন্ট You আপনি এটি প্যাটার্ন.ম্যাচেস () এবং প্যাটারন ডটকমপ্লে () এর মাধ্যমে ব্যবহার করতে পারেন। এই দুজনের মধ্যে # ডিফারেন্স। মেলে () - কোনও পাঠ্য (স্ট্রিং) প্রদত্ত নিয়মিত এক্সপ্রেশন কমপল () - এর সাথে প্যাটার্নের রেফারেন্স তৈরি করে কিনা তা দ্রুত পরীক্ষা করে দেখুন । তাই একাধিক পাঠ্যের বিপরীতে নিয়মিত অভিব্যক্তি মেলে একাধিকবার ব্যবহার করতে পারেন।

রেফারেন্সের জন্য:

public static void main(String[] args) {
     //single time uses
     String text="The Moon is far away from the Earth";
     String pattern = ".*is.*";
     boolean matches=Pattern.matches(pattern,text);
     System.out.println("Matches::"+matches);

    //multiple time uses
     Pattern p= Pattern.compile("ab");
     Matcher  m=p.matcher("abaaaba");
     while(m.find()) {
         System.out.println(m.start()+ " ");
     }
}
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.