लैटिन वर्णों में खोज सीमित करें


9

मैं अंग्रेजी भाषा + नंबरों पर प्रयुक्त वर्णों तक खोज को सीमित करना चाहता हूं। इसका कारण यह है कि mysql लॉग पर सबसे धीमे प्रश्नों को देखते हुए मुझे सबसे अधिक अरब, रूसी और चीनी पात्रों में खोजें मिलीं, इसलिए मैं उन्हें छोड़ना चाहता हूं और इसके बजाय एक त्रुटि संदेश प्रदर्शित करना चाहता हूं।


यदि आप यह विस्तार करते हैं कि आप अपनी त्रुटि को कैसे प्रदर्शित करना चाहते हैं तो मैं इसे शामिल करने के लिए अपने उत्तर को संशोधित करूँगा
बोसको

मैं खोज फ़ॉर्म में नीचे या ऊपर खोज पृष्ठ में दिखाने के लिए त्रुटि चाहूंगा।
माइकल रोजर्स

जवाबों:


10

यह समाधान एक नियमित अभिव्यक्ति को लागू करके स्ट्रिंग्स को खोजता है जो केवल कॉमन और लैटिन यूनिकोड लिपियों के पात्रों से मेल खाता है।


नियमित अभिव्यक्तियों के साथ लैटिन वर्णों का मिलान

मैंने अभी-अभी अपना दिमाग स्टैक ओवरफ्लो पर उड़ाया था । जैसा कि यह पता चला है, नियमित अभिव्यक्तियों में पूरे यूनिकोड श्रेणियों से मेल खाने के लिए एक तंत्र है, जिसमें पूरे यूनिकोड "स्क्रिप्ट" को निर्दिष्ट करने के लिए मान शामिल हैं , प्रत्येक अलग-अलग लेखन प्रणालियों में उपयोग किए जाने वाले वर्णों के समूहों के अनुरूप है।

यह \pघुंघराले ब्रेसिज़ में यूनिकोड श्रेणी के पहचानकर्ता द्वारा अनुसरण किए गए मेटा-चरित्र का उपयोग करके किया जाता है - इसलिए लैटिन या सामान्य लिपियों[\p{Common}\p{Latin}] में किसी एक वर्ण से मेल खाता है - इसमें विराम चिह्न, अंक और विविध चिह्न शामिल हैं।

जैसा कि @Paul 'स्पैरो हॉक' बीरन बताते हैं , विषय के स्ट्रिंग को यूनिकोड के रूप में ट्रीट करने के लिए पीएचपी के पीसीआर फंक्शन के लिए रेग्युलर एक्सप्रेशन के अंत में u पैटर्न मॉडिफायर फ्लैग सेट किया जाना चाहिए UTF-8

सभी एक साथ, पैटर्न

/^[\p{Latin}\p{Common}]+$/u

लैटिन और कॉमन यूनिकोड लिपियों में एक या अधिक वर्णों से बना एक संपूर्ण स्ट्रिंग से मेल खाएगा।


खोज स्ट्रिंग को फ़िल्टर करना

एक अच्छी जगह एक खोज स्ट्रिंग रोकना है कार्रवाई इसे तुरंत आग के रूप में पहले वर्डप्रेस क्वेरी निष्पादित करता है। अधिक देखभाल के साथ , यह एक फिल्टर का उपयोग करके भी पूरा किया जा सकता है ।pre_get_postsrequest

function wpse261038_validate_search_characters( $query ) {
  // Leave admin, non-main query, and non-search queries alone
  if( is_admin() || !$query->is_main_query() || !$query->is_seach() )
    return;

  // Check if the search string contains only Latin/Common Unicode characters
  $match_result = preg_match( '/^[\p{Latin}\p{Common}]+$/u', $query->get( 's' ) );

  // If the search string only contains Latin/Common characters, let it continue
  if( 1 === $match_result )
    return;

  // If execution reaches this point, the search string contains non-Latin characters
  //TODO: Handle non-Latin search strings
  //TODO: Set up logic to display error message
}

add_action( 'pre_get_posts', 'wpse261038_validate_search_characters' );

अस्वीकृत खोजों पर प्रतिक्रिया

एक बार जब यह निर्धारित हो जाता है कि खोज स्ट्रिंग में गैर-लैटिन वर्ण हैं, तो आप WP_Query::set()क्वेरी को संशोधित करने के लिए इसका उपयोग कर सकते हैं इसे क्वेरी संस्करण नाम दिया गया है - इस प्रकार SQL क्वेरी को प्रभावित करना वर्डप्रेस बाद में रचना और निष्पादित करता है।

सबसे प्रासंगिक क्वेरी चर संभवतः निम्नलिखित हैं:

  • sखोज स्ट्रिंग के अनुरूप क्वेरी चर है। इसे nullएक रिक्त स्ट्रिंग ( '') पर सेट करने से परिणाम होगा कि वर्डप्रेस अब क्वेरी को एक खोज के रूप में नहीं मान रहा है - कई बार इसका परिणाम संग्रह के टेम्पलेट में होता है जो सभी पोस्ट या साइट के फ्रंट-पेज को प्रदर्शित करता है, जो दूसरे के मूल्यों पर निर्भर करता है। क्वेरी vars। ' 'हालाँकि, इसे एक ही स्थान पर सेट करना ( ), इसके परिणामस्वरूप वर्डप्रेस इसे एक खोज के रूप में पहचानता है, और इस प्रकार search.phpटेम्पलेट को प्रदर्शित करने का प्रयास करता है।
  • page_id उपयोगकर्ता को आपकी पसंद के एक विशिष्ट पृष्ठ पर निर्देशित करने के लिए इस्तेमाल किया जा सकता है।
  • post__inक्वेरी को पदों के एक विशिष्ट चयन के लिए प्रतिबंधित कर सकता है। एक असंभव पोस्ट आईडी के साथ इसे एक सरणी में सेट करके, यह सुनिश्चित करने के लिए एक उपाय के रूप में सेवा कर सकता है कि क्वेरी बिल्कुल कुछ भी नहीं लौटाती है

मन में ऊपर, आप search.phpकोई परिणाम नहीं के साथ टेम्पलेट लोड करके एक बुरी खोज का जवाब देने के लिए निम्नलिखित कर सकते हैं :

function wpse261038_validate_search_characters( $query ) {
  // Leave admin, non-main query, and non-search queries alone
  if( is_admin() || !$query->is_main_query() || !$query->is_seach() )
    return;

  // Check if the search string contains only Latin/Common Unicode characters
  $match_result = preg_match( '/^[\p{Latin}\p{Common}]+$/u', $query->get( 's' ) );

  // If the search string only contains Latin/Common characters, let it continue
  if( 1 === $match_result )
    return;

  $query->set( 's', ' ' ); // Replace the non-latin search with an empty one
  $query->set( 'post__in', array(0) ); // Make sure no post is ever returned

  //TODO: Set up logic to display error message
}

add_action( 'pre_get_posts', 'wpse261038_validate_search_characters' );

त्रुटि प्रदर्शित करना

जिस तरह से आप वास्तव में त्रुटि संदेश प्रदर्शित करते हैं वह आपके आवेदन और आपके विषय की क्षमताओं पर अत्यधिक निर्भर है - ऐसे कई तरीके हैं जो यह किया जा सकता है। यदि आपकी थीम get_search_form()इसमें खोज टेम्प्लेट कहती है, तो सबसे आसान उपाय यह है कि खोज प्रपत्र के तुरंत बाद अपनी त्रुटि को उत्पन्न करने के लिए एक pre_get_search_formएक्शन हुक का उपयोग किया जाए:

function wpse261038_validate_search_characters( $query ) {
  // Leave admin, non-main query, and non-search queries alone
  if( is_admin() || !$query->is_main_query() || !$query->is_seach() )
    return;

  // Check if the search string contains only Latin/Common Unicode characters
  $match_result = preg_match( '/^[\p{Latin}\p{Common}]+$/u', $query->get( 's' ) );

  // If the search string only contains Latin/Common characters, let it continue
  if( 1 === $match_result )
    return;

  $query->set( 's', ' ' ); // Replace the non-latin search with an empty one
  $query->set( 'post__in', array(0) ); // Make sure no post is ever returned

  add_action( 'pre_get_search_form', 'wpse261038_display_search_error' );
}

add_action( 'pre_get_posts', 'wpse261038_validate_search_characters' );

function wpse261038_display_search_error() {
  echo '<div class="notice notice-error"><p>Your search could not be completed as it contains characters from non-Latin alphabets.<p></div>';
}

त्रुटि संदेश प्रदर्शित करने के लिए कुछ अन्य संभावनाओं में शामिल हैं:

  • यदि आपकी साइट जावास्क्रिप्ट का उपयोग करती है जो "फ्लैश" या "मोडल" संदेश प्रदर्शित कर सकती है (या आप अपने आप में इस तरह की क्षमता जोड़ते हैं), तो पृष्ठ-लोड पर संदेश प्रदर्शित करने के लिए तर्क जोड़ें जब एक विशिष्ट चर सेट किया जाता है, तो एक wp_enqueue_scriptहुक जोड़ें इससे $priorityभी बड़ा जो कि जावास्क्रिप्ट को संकलित करता है, और wp_localize_script()आपके त्रुटि संदेश को शामिल करने के लिए उस चर को सेट करने के लिए उपयोग करता है।
  • wp_redirect()उपयोगकर्ता को अपनी पसंद के URL पर भेजने के लिए उपयोग करें (इस पद्धति के लिए अतिरिक्त पृष्ठ लोड की आवश्यकता है)।
  • एक PHP चर सेट करें या एक विधि लागू करें जो आपके विषय / प्लगइन को त्रुटि के बारे में सूचित करेगा, ताकि वह इसे प्रदर्शित कर सके जहां उपयुक्त हो।
  • सेट sकरने के लिए क्वेरी चर ''के बजाय ' 'और उपयोग page_idके स्थान पर post__inआदेश अपने द्वारा चयनित किसी पेज पर लौटने के लिए में।
  • क्वेरी परिणामों में अपनी त्रुटि वाले नकली ऑब्जेक्ट को इंजेक्ट करने के लिए loop_startहुक का उपयोग करें WP_Post- यह निश्चित रूप से एक बदसूरत हैक है और आपके विशेष विषय के साथ सही नहीं लग सकता है, लेकिन इसका "वांछनीय परिणाम" संदेश को दबाने का संभावित वांछनीय दुष्प्रभाव है।
  • template_includeअपने थीम या प्लगइन में कस्टम टेम्पलेट के साथ खोज टेम्पलेट को स्वैप करने के लिए एक फिल्टर हुक का उपयोग करें जो आपकी त्रुटि प्रदर्शित करता है।

प्रश्न में विषय की जांच के बिना, यह निर्धारित करना मुश्किल है कि आपको कौन सा मार्ग लेना चाहिए।


2

आप PHP में एक मान्यता समारोह में डालकर ऐसा करेंगे कि नियमित अभिव्यक्ति जैसे इनपुट का परीक्षण कर सकें ^[a-zA-Z0-9,.!?' ]*

तो यह इस तरह दिखेगा:

if ( preg_match( "^[a-zA-Z0-9,.!?'" ]*", {search variable} ) ) {
   // Success
} else {
   // Fail
}

RexEx मैं सभी वर्णों के लिए इस्तेमाल किया A-Z, a-z, 0-9, साथ ही ,, ., !, ?, ', ", और (स्थान)।


2

EDIT: यह समाधान अनुशंसित नहीं है

नीचे मेरा समाधान एक हैक है जो बाइट्स की व्यवस्था को देखते हुए जादुई रूप से दिव्य वर्णमाला के प्रयास में PHP के mbstring कार्यों का दुरुपयोग करता है जो स्ट्रिंग की रचना करता है। यह एक बहुत बुरा विचार है और त्रुटि के लिए अत्यधिक संभावना है

कृपया अधिक सरल और अधिक विश्वसनीय समाधान के लिए मेरे अन्य उत्तर को देखें ।


गैर-लैटिन अक्षर का उपयोग करके खोजों को रोकने का एक मतलब यह है कि यह देखने के लिए PHP के mb_detect_encoding()फ़ंक्शन का उपयोग करना है कि क्या खोज स्ट्रिंग चरित्र एन्कोडिंग के कस्टम चयन में से एक के अनुरूप है। एक अच्छी जगह यह करने के लिए है कार्रवाई के रूप में यह आग ठीक पहले क्वेरी निष्पादित किया जाता है,।pre_get_posts

आपके द्वारा खोज निर्धारित करने के बाद आप वास्तव में क्या करते हैं एक अवैध एन्कोडिंग का उपयोग करना वास्तव में विशिष्ट अनुप्रयोग है। यहाँ मैंने खोज क्वेरी को एक एकल स्थान पर सेट किया है ताकि यह सुनिश्चित किया जा सके कि वर्डप्रेस अभी भी खोज के रूप में क्वेरी की व्याख्या करता है, और इस तरह अभी भी search.phpटेम्पलेट लोड करता है (और उपयोगकर्ता को फ्रंट-पेज पर निर्देशित नहीं करता है, जैसा कि खोज स्ट्रिंग के समय होता है। एक खाली तार)। मैं एक असंभव पोस्ट आईडी के साथ एक सरणी में सेटिंग'post__in' का एक जोड़ा एहतियात लेता हूं ताकि यह सुनिश्चित हो सके कि बिल्कुल कुछ भी वापस नहीं किया गया है

वैकल्पिक रूप से, आप अपने कस्टम त्रुटि संदेश के साथ उपयोगकर्ता को एक पृष्ठ पर निर्देशित करने के लिए खोज स्ट्रिंग को nullसेट और सेट करने पर विचार कर सकते हैं page_id

function wpse261038_validate_search_query_encoding( $query ) {
  $valid_encodings = array( 'Windows-1252' );

  // Ignore admin, non-main query, and non-search queries
  if( is_admin() || !$query->is_main_query() || !$query->is_seach() )
    return;

  // Retrieve the encoding of the search string (if it's one listed in $valid_encodings)
  $search_encoding = mb_detect_encoding( $query->get( 's' ), $valid_encodings, true );

  // If the search encoding is one in $valid_encodings, leave the query as-is
  if( in_array( $search_encoding, $valid_encodings ) )
    return;

  // If it wasn't, sabotage the search query
  $query->set( 's', ' ' );
  $query->set( 'post__in', array(0) );

  // Set up your error message logic here somehow, perhaps one of the following:
  // - Add a template_include filter to load a custom error template
  // - Add a wp_enqueue_scripts hook with a greater priority than your theme/plugin's, and
  //     use wp_localize_script() in the hook to pass an error message for your JavaScript
  //     to display
  // - Perform a wp_redirect() to send the user to the URL of your choice
  // - Set a variable with an error message which your theme or plugin can display
}

add_action( 'pre_get_posts', 'wpse261038_validate_search_query_encoding' );

एनकोडिंग चुनना

मैंने PHP द्वारा समर्थित सभी डिफ़ॉल्ट एनकोडिंग के खिलाफ विभिन्न अल्फ़ाज़ों में कुछ डमी स्ट्रिंग्स की तुलना करते हुए एक कवरेज टेस्ट लिखा । यह किसी भी खिंचाव से परिपूर्ण नहीं है (मुझे नहीं पता कि मेरे डमी स्ट्रिंग्स कितने यथार्थवादी हैं, और यह जापानी पहचान का पता लगाने के लिए लगता है), लेकिन यह उम्मीदवारों को निर्धारित करने के लिए कुछ हद तक उपयोगी है। आप इसे यहां कार्रवाई में देख सकते हैं ।

उस परीक्षण द्वारा चिह्नित किए गए संभावित चरित्र एन्कोडिंग पर शोध करने के बाद, ऐसा लगता है जैसे Windows-1252आपकी ज़रूरतों के लिए सही विकल्प है, लैटिन वर्णमाला के साथ-साथ आम लैटिन भाषाओं के लिए उच्चारण।

ISO-8859वर्ण सेटों का चयन एक अन्य व्यवहार्य विकल्प होना चाहिए , हालाँकि जिन कारणों से मैं अपने सिर को चारों ओर नहीं लपेट सकता , उन्हें अलग-अलग एन्कोडिंग के रूप में सूचीबद्ध करने के बावजूद mb_फ़ंक्शन अलग- ISO-8859अलग वर्ण सेटों के बीच अंतर नहीं करते हैं ।

कुछ अन्य सामान्य पात्रों को अनुमति देने के लिए, आप जोड़ने पर भी विचार कर सकते हैं HTML-ENTITIES


ऐसा लगता है कि जिस तंत्र द्वारा mbstring फ़ंक्शन काम करता है वह एन्कोडिंग के बीच अंतर करने में असमर्थ हैISO-8859
बोसको

मैंने सीखा है कि मेरा जुड़ा हुआ परीक्षण गलत और भ्रामक है - बाइट अनुक्रमों के आधार पर mbstring फ़ंक्शन काम करते हैं, इसलिए जब एक एन्कोडिंग बाइट अनुक्रमों का उपयोग कर सकता है जो सूचीबद्ध वर्णमालाओं का समर्थन कर सकता है, तो यह वास्तव में नहीं करता है कि एन्कोडिंग वास्तव में उन का समर्थन करती है पात्र। इस प्रकार, एन्कोडिंग का परीक्षण करके तारों के अक्षर को छानना एक विश्वसनीय तंत्र नहीं है । कृपया मेरे अन्य उत्तर पर विचार करें।
बोस्को २co ’

1

जैसा कि मैंने @MichaelRogers को समझाने की कोशिश की, जब उन्होंने कई दिन पहले इसी तरह का प्रश्न पोस्ट किया था, स्ट्रिंग में प्रयुक्त वर्ण सेट (या स्क्रिप्ट) को जानना उस स्ट्रिंग की भाषा का पता लगाने के लिए पर्याप्त नहीं है

इस प्रकार, जबकि @bosco द्वारा विस्तृत विधि रूसी, आदि तार (नीचे 2 सुधार के साथ) को हटा देगी , यह आपकी खोजों को अंग्रेजी तक सीमित नहीं करेगा ।

इसे देखने के लिए, प्रयास करें:

$strings = array (
    'I\'m sorry',                   // English
    'Je suis désolé',               // French
    'Es tut mir Leid',              // German
    'Lorem ipsum dolor sit amet',   // Lorem ipsum
    'أنا سعيد',                     // Arabic
    'я счастлив',                   // Russian
    '我很高兴',                     // Chinese (Simplified)
    '我很高興',                     // Chinese (Traditional)
    ) ;
foreach ($strings as $s) {
    if (preg_match ('/^[\p{Latin}\p{Common}]+$/u', $s) === 1) {
        echo "$s: matches latin+common\n" ;
        }
    else {
        echo "$s: does not match latin+common\n" ;
        }
    }

[ नोट: ऊपर दिए गए 2 सुधार जो @bosco को प्रदान किए गए हैं:

  1. पैटर्न एक स्ट्रिंग संलग्न है (आवश्यक रूप से सही PHP के लिए आवश्यक है)
  2. /uसंशोधक को जोड़ा गया (UTF-8 एन्कोडेड के रूप में पैटर्न और विषय के इलाज के लिए आवश्यक है, PHP देखें : रेगेक्स पैटर्न संशोधक ]

जो उत्पादन करेगा:

I'm sorry: matches latin+common
Je suis désolé: matches latin+common
Es tut mir Leid: matches latin+common
Lorem ipsum dolor sit amet: matches latin+common
أنا سعيد: does not match latin+common
я счастлив: does not match latin+common
我很高兴: does not match latin+common
我很高興: does not match latin+common

[ नोट: मैं अंग्रेजी, फ्रेंच और कुछ जर्मन बोलता हूं (और लोरम ipsum :-) का एक सा है , लेकिन अरबी, रूसी और चीनी के लिए Google अनुवाद पर निर्भर है]

जैसा कि आप देख सकते हैं, लैटिन लिपि की जाँच पर निर्भर होना सुनिश्चित नहीं करेगा कि आपके पास अंग्रेजी है।

StackOverflow पर कई थ्रेड्स हैं (जैसे, PHP में स्ट्रिंग से भाषा का पता लगाएँ ) जो विषय पर अधिक जानकारी प्रदान करते हैं।


मुझे एक दोस्ताना, पंडिताऊ नोट छोड़ दो: Lorem ipsum एक भाषा नहीं है, कोई बोलता है कहने के लिए "lorem ipsum" कह रही है कि कोई बोलता है की तरह है "हैलो दुनिया" :) की भाषा Lorem ipsum है पुराने लैटिन , और कोई, "lorem ipsum "का अर्थ " हैलो वर्ल्ड "नहीं है :) वास्तव में यह " डोलरेम ipsum "के लिए एक टाइपो है जिसका अर्थ है " दर्द खुद " या ऐसा ही कुछ।
गमजप

@gmazzap मुझे पता है, यह एक मजाक था (इसलिए ":-)")। मैंने इस बात को पुष्ट करने के लिए लोरेम इप्सम को शामिल किया कि स्क्रिप्ट की जाँच करने से भाषा का परीक्षण नहीं होता है ।
पॉल 'स्पैरो हॉक' बीरन

और अधिक पांडित्यपूर्ण होने के लिए, जैसा कि लिपसम डॉट कॉम पर कहा गया है , "लोरेम इप्सम सेक्शन 1.10.32 और 1.10.33 में" डे फिनिबस बोनोरम एट मालोरम "(द एक्सट्रीमस ऑफ गुड एंड एविल) से आता है, जो सिसरो द्वारा 45 में लिखा गया है। ईसा पूर्व। " लेकिन इसमें विभिन्न "यादृच्छिकताएं" भी हैं जो इसे देशी लैटिन स्पीकर के लिए निरर्थक बनाती हैं, इसलिए यह वास्तव में "पुरानी लैटिन" नहीं है, बल्कि पूरी तरह से बनाई गई "भाषा" है।
पॉल 'स्पैरो हॉक' बिरनो

आह, अच्छा कैच @ पॉल'स्प्रेहॉव'बिरॉन! मैं नियमित अभिव्यक्ति को ठीक करने के लिए अपने उत्तर को अपडेट करूँगा और स्पष्ट करूँगा कि मेरा समाधान क्या करता है।
बोस्को

1
मुझे परवाह नहीं है अगर व्यक्ति स्पेनिश में टाइप करता है। इसे कड़ाई से अंग्रेजी भाषा की आवश्यकता नहीं है। मैंने कहा कि अंग्रेजी भाषा में इस्तेमाल किए जाने वाले अक्षर ए से जेड तक (कैप और नो कैप) + संख्या में हैं। यदि अन्य भाषाएं समान वर्णों का उपयोग करती हैं तो मेरे द्वारा ठीक है। जो मैं अनुमति नहीं देना चाहता हूं वह है सिरिलिक, कांजी, अरबी अक्षर (नाम नहीं जानते), और कुछ भी जो एए-जेड + 0-9 नहीं है। भाषा कोई मायने नहीं रखती।
माइकल रोजर्स
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.