2012-04-07 23 views
7

क्या दो Pattern वस्तुओं की तुलना करने का कोई आसान तरीका है?जावा दो पैटर्न वस्तुओं की तुलना

मेरे पास Pattern है जो कोड में टिप्पणियों की जांच के लिए regex "//" का उपयोग करके संकलित किया गया है।

चूंकि टिप्पणियों का वर्णन करने के लिए कई रेगेक्स हैं, इसलिए मैं उन्हें अंतर करने का एक तरीका ढूंढना चाहता हूं।

यह कैसे किया जा सकता है? Pattern कक्षा equals विधि लागू नहीं करती है।

उत्तर

4

शायद मैं इस प्रश्न को पूरी तरह समझ नहीं पा रहा हूं। लेकिन जैसा कि आप निम्न उदाहरण में देख सकते हैं, प्रत्येक जावा ऑब्जेक्ट के लिए एक डिफ़ॉल्ट java.lang.Object.equals(Object) विधि है। यह विधि ऑब्जेक्ट्स के संदर्भों की तुलना करती है, यानी == ऑपरेटर का उपयोग करता है।

 

package test; 

import java.util.regex.Pattern; 

public class Main { 

    private static final Pattern P1 = Pattern.compile("//.*"); 
    private static final Pattern P2 = Pattern.compile("//.*"); 

    public static void main(String[] args) { 
    System.out.println(P1.equals(P1)); 
    System.out.println(P1.equals(P2)); 
    System.out.println(P1.pattern().equals(P1.pattern())); 
    System.out.println(P1.pattern().equals(P2.pattern())); 
    } 
} 
 

आउटपुट:

 

true 
false 
true 
true 
 
2

Pattern लेकिन String नहीं करता है। क्यों न केवल रेगेक्स की तुलना करें, जिससे Pattern एस संकलित किए गए थे?

0

आप स्ट्रिंग अभ्यावेदन जहाँ से पैटर्न बनाया गया है की तुलना कर सकते हैं:

Pattern p1 = getPattern1(); 
Pattern p2 = getPattern2(); 
if (p1.pattern().equals(p2.pattern())){ 
    // your code here 
} 
4

आप pattern() या toString बुला का परिणाम की तुलना द्वारा Pattern वस्तुओं की तुलना कर सकते हैं लेकिन यह वही नहीं करता जो आप चाहते हैं (यदि मैं आपका प्रश्न सही ढंग से समझता हूं)। विशेष रूप से, यह उन तारों की तुलना करता है जो Pattern.compile(...) फैक्ट्री विधि में पारित किए गए थे।

परीक्षण करने का कोई आसान तरीका नहीं है कि दो गैर-समान रेगेक्स बराबर हैं या नहीं। उदाहरण के लिए ".+" और "..*" बराबर regexes का प्रतिनिधित्व करते हैं, लेकिन Pattern API का उपयोग करके इसे निर्धारित करने के लिए कोई सीधा-आगे तरीका नहीं है।

(मैं भी पता नहीं है, तो समस्या है सैद्धांतिक रूप से व्याख्या करने योग्य ... सामान्य मामले में।)


मैं भी स्वीकार किए जाते हैं जवाब पर टिप्पणी करना चाहते। लेखक कुछ कोड प्रदान करता है कि उनका दावा है कि दिखाता है कि पैटर्न की equals विधि Object से विरासत में मिली है। वास्तव में, वह जो आउटपुट देख रहा है वह संगत है ... लेकिन यह दिखाता है।

यह जानने का सही तरीका है कि यह मामला जावडोक को देखना है ... जहां equals विधि विरासत विधियों की सूची में सूचीबद्ध है। यह निश्चित है।

तो उदाहरण क्यों नहीं दिखाता है कि लेखक क्या दिखाता है?

  1. दो विधियों के लिए एक ही तरीके से व्यवहार करना संभव है, लेकिन अलग-अलग लागू किया जा सकता है। अगर हम ब्लैक बॉक्स के रूप में Pattern कक्षा का इलाज करते हैं, तो हम यह नहीं दिखा सकते कि यह नहीं हो रहा है। (या कम से कम ... प्रतिबिंब का उपयोग किए बिना नहीं।)

  2. लेखक ने इसे केवल एक मंच पर चलाया है। अन्य प्लेटफॉर्म अलग-अलग व्यवहार कर सकते हैं।

दूसरी बात पर, मेरे याद है कि Pattern के पहले कार्यान्वयन में (जावा 1.4 में) Pattern.compile(...) तरीकों हाल ही में संकलित पैटर्न की एक कैश वस्तुओं रखा है। आप एक खास पैटर्न स्ट्रिंग दो बार संकलित हैं, तो दूसरी बार आप एक ही वस्तु रूप में पहली बार वापस आ गया था मिल सकता है। इससे टेस्ट कोड आउटपुट हो जाएगा:

true 
    true 
    true 
    true 

लेकिन यह क्या दिखाता है? क्या यह दिखाता है कि PatternObject.equals ओवरराइड करता है? नहीं!

सबक यहाँ है कि आप पता लगाना चाहिए कि कैसे एक जावा पुस्तकालय विधि बर्ताव javadocs को देखकर मुख्य रूप से है:

  • आप एक "ब्लैक बॉक्स" परीक्षण लिखने हैं, तो आप आकर्षित करने के लिए उत्तरदायी हैं गलत निष्कर्ष ... या कम से कम, निष्कर्ष जो सभी प्लेटफार्मों के लिए सच नहीं हो सकते हैं।

  • आप पर "कोड को पढ़ने के लिए" अपने निष्कर्ष का आधार हैं, तो आप निष्कर्ष है कि अन्य प्लेटफार्मों के लिए अमान्य हैं ड्राइंग के जोखिम को चलाते हैं।


1 - यहां तक ​​कि अगर मेरी याद गलत है, इस प्रकार का कार्यान्वयन Pattern.compile(...) तरीकों के लिए javadocs के अनुरूप होगा। वे यह नहीं कहते कि प्रत्येक compile कॉल एक नया Pattern ऑब्जेक्ट देता है।

+0

अगर आप तुलना 'pattern' आप झंडे को याद करेंगे:

यहाँ एल्गोरिथ्म के एक जावा कार्यान्वयन है। –

+0

@ मार्कस मलकुस्च - हां, यह एक अन्य कारण है कि 'पैटर्न()' का उपयोग करके 'पैटर्न' ऑब्जेक्ट की तुलना क्यों समस्याग्रस्त हो सकती है। –

+0

पैटर्न ऑब्जेक्ट्स को स्वचालित रूप से कैश नहीं किया गया है। सबूत के रूप में, एपीआई दस्तावेज़ चेतावनी देते हैं कि 'पैटर्न.मैट्स()' और 'स्ट्रिंग # मैचों()' पैटर्न ऑब्जेक्ट का पुन: उपयोग करने की अनुमति नहीं देते हैं, और इसलिए लूप में दोहराए गए कॉल के लिए उपयोग नहीं किया जाना चाहिए। (स्कैनर क्लास * करता है * यह सभी पैटर्न का उपयोग करता है, लेकिन यह आंतरिक रूप से संभालता है।) –

3

रहस्यमय कारणों के लिए, पैटर्न वस्तु बराबरी को लागू नहीं करता है()। उदाहरण के लिए, इस सरल unittest असफल हो जायेगी:

@Test 
    public void testPatternEquals() { 
     Pattern p1 = Pattern.compile("test"); 
     Pattern p2 = Pattern.compile("test"); 
     assertEquals(p1.toString(), p2.toString()); // succeeds! 
    } 
:

@Test 
    public void testPatternEquals() { 
     Pattern p1 = Pattern.compile("test"); 
     Pattern p2 = Pattern.compile("test"); 
     assertEquals(p1, p2); // fails! 
    } 

इसका सबसे सामान्य तरीके को (जो स्ट्रिंग पैटर्न बनाने के लिए इस्तेमाल रिटर्न) पैटर्न वस्तुओं की स्ट्रिंग अभ्यावेदन तुलना करने के लिए हो रहा है

0

मैं मैं सवाल का अंदाजा हो लगता है और जब से मैं Pattern रों तुलना करने के लिए तरीके की खोज की मैं यहाँ अंत (दो साल बहुत देर हो चुकी शायद, ठीक है, खेद ...)।

मैं परीक्षण लिख रहा हूँ और मुझे पता है कि अगर मेरा एक विधि की उम्मीद पैटर्न देता है की जरूरत है। जबकि toString() या pattern() के माध्यम से पाठ समान हो सकता है, झंडे अलग-अलग हो सकते हैं और परिणाम का उपयोग करते समय परिणाम अप्रत्याशित होगा।

कुछ समय पहले मैं toString() की अपने ही सामान्य कार्यान्वयन लिखा था। यह private वाले सभी फ़ील्ड एकत्र करता है और एक स्ट्रिंग बनाता है जिसका उपयोग लॉगिंग के लिए और स्पष्ट रूप से परीक्षण के लिए किया जा सकता है। यह दिखाता है कि दो बराबर पैटर्न संकलित करते समय root और matchRoot फ़ील्ड अलग थे। यह मानते हुए कि वे दोनों समानता के लिए प्रासंगिक नहीं हैं और चूंकि flag फ़ील्ड है, तो मेरा समाधान बिल्कुल सही नहीं है, तो सही है।

/** 
* Don't call this method from a <code>toString()</code> method with 
* <code>useExistingToString</code> set to <code>true</code>!!! 
*/ 
public static String toString(Object object, boolean useExistingToString, String... ignoreFieldNames) { 
    if (object == null) { 
    return null; 
    } 

    Class<? extends Object> clazz = object.getClass(); 
    if (useExistingToString) { 
    try { 
     // avoid the default implementation Object.toString() 
     Method methodToString = clazz.getMethod("toString"); 
     if (!methodToString.getDeclaringClass().isAssignableFrom(Object.class)) { 
     return object.toString(); 
     } 
    } catch (Exception e) { 
    } 
    } 

    List<String> ignoreFieldNameList = Arrays.asList(ignoreFieldNames); 
    Map<String, Object> fields = new HashMap<String, Object>(); 
    while (clazz != null) { 
    for (Field field : clazz.getDeclaredFields()) { 
     String fieldName = field.getName(); 
     if (ignoreFieldNameList.contains(fieldName) || fields.containsKey(fieldName)) { 
     continue; 
     } 

     boolean accessible = field.isAccessible(); 
     if (!accessible) { 
     field.setAccessible(true); 
     } 
     try { 
     Object fieldValue = field.get(object); 
     if (fieldValue instanceof String) { 
      fieldValue = stringifyValue(fieldValue); 
     } 
     fields.put(fieldName, fieldValue); 
     } catch (Exception e) { 
     fields.put(fieldName, "-inaccessible- " + e.getMessage()); 
     } 
     if (!accessible) { 
     field.setAccessible(false); 
     } 
    } 
    // travel upwards in the class hierarchy 
    clazz = clazz.getSuperclass(); 
    } 

    return object.getClass().getName() + ": " + fields; 
} 

public static String stringifyValue(Object value) { 
    if (value == null) { 
    return "null"; 
    } 
    return "'" + value.toString() + "'"; 
} 

और परीक्षण हरा है:

String toString1 = Utility.toString(Pattern.compile("test", Pattern.CASE_INSENSITIVE), false, "root", "matchRoot"); 
String toString2 = Utility.toString(Pattern.compile("test", Pattern.CASE_INSENSITIVE), false, "root", "matchRoot"); 
assertEquals(toString1, toString2); 
0

निर्धारित करने के लिए है कि क्या दो Pattern वस्तुओं बराबर हैं, ऐसा करने का सरलतम बात वास्तविक स्ट्रिंग पैटर्न और झंडे कि बनाने के लिए इस्तेमाल की तुलना करना है पैटर्न:

boolean isPatternEqualToPattern(final Pattern p1, final Pattern p2) { 
    return p1.flags() == p2.flags() && 
     p1.pattern().equals(p2.pattern()); 
} 
0

मुझे पता है कि ऑटोटाटा आपकी समस्या का समाधान कर सकता है। लेकिन वह शायद जटिल हो सकता है। लगभग, आपको कम से कम pattern.pattern() और pattern.flags() की तुलना करनी चाहिए, हालांकि यह तय करने के लिए पर्याप्त नहीं है कि दो रेगेक्स बराबर हैं या नहीं।

0

हालांकि अन्य उत्तरों समस्या को हल कर सकते हैं, मुझे नहीं लगता कि वे समस्या का असली जवाब हैं।

यदि आप वास्तव में दो पैटर्न की तुलना करना चाहते हैं तो आप अनिवार्य रूप से दो नियमित भाषाओं की तुलना करेंhttps://cs.stackexchange.com/questions/12876/equivalence-of-regular-expressions

एक तेज विधि की जाँच करने के लिए नियमित रूप से भाषाओं के तुल्यता Hopcroft और कार्प एल्गोरिथ्म (हांगकांग) है:

ऐसा करने के लिए सीएस stackexchange पहले से ही एक समाधान पोस्ट किया गया है। http://algs4.cs.princeton.edu/65reductions/HopcroftKarp.java.html

संबंधित मुद्दे