ஜாவாஸ்கிரிப்ட் ஸ்ட்ரிங் பேட்டர்ன் மேட்சிங்கை மேம்படுத்துவதற்கான மேம்பட்ட நுட்பங்களை ஆராயுங்கள். வேகமான, திறமையான ஸ்ட்ரிங் செயலாக்க இன்ஜினை அடிப்படையிலிருந்து எவ்வாறு உருவாக்குவது என்பதை அறிக.
ஜாவாஸ்கிரிப்டின் மையத்தை மேம்படுத்துதல்: ஒரு உயர்-செயல்திறன் கொண்ட ஸ்ட்ரிங் பேட்டர்ன் மேட்சிங் இன்ஜினை உருவாக்குதல்
மென்பொருள் மேம்பாட்டின் பரந்த உலகில், ஸ்ட்ரிங் செயலாக்கம் ஒரு அடிப்படை மற்றும் எங்கும் நிறைந்த பணியாக உள்ளது. ஒரு டெக்ஸ்ட் எடிட்டரில் உள்ள எளிய 'find and replace' முதல், நெட்வொர்க் டிராஃபிக்கை தீங்கிழைக்கும் பேலோடுகளுக்காக ஸ்கேன் செய்யும் அதிநவீன ஊடுருவல் கண்டறிதல் அமைப்புகள் வரை, உரைக்குள் பேட்டர்ன்களை திறமையாகக் கண்டறியும் திறன் நவீன கணினியின் ஒரு மூலக்கல்லாகும். ஜாவாஸ்கிரிப்ட் டெவலப்பர்களுக்கு, செயல்திறன் நேரடியாக பயனர் அனுபவத்தையும் சர்வர் செலவுகளையும் பாதிக்கும் ஒரு சூழலில் செயல்படுபவர்களுக்கு, ஸ்ட்ரிங் பேட்டர்ன் பொருத்தத்தின் நுணுக்கங்களைப் புரிந்துகொள்வது ஒரு கல்விப் பயிற்சி மட்டுமல்ல - இது ஒரு முக்கியமான தொழில்முறைத் திறமையாகும்.
ஜாவாஸ்கிரிப்டின் உள்ளமைக்கப்பட்ட முறைகளான String.prototype.indexOf()
, includes()
, மற்றும் சக்திவாய்ந்த RegExp
இன்ஜின் ஆகியவை அன்றாடப் பணிகளுக்கு நமக்கு நன்றாக சேவை செய்தாலும், அதிக செயல்திறன் தேவைப்படும் பயன்பாடுகளில் அவை செயல்திறன் தடைகளாக மாறக்கூடும். ஒரு பெரிய ஆவணத்தில் ஆயிரக்கணக்கான முக்கிய வார்த்தைகளைத் தேட வேண்டியிருக்கும் போது, அல்லது மில்லியன் கணக்கான பதிவு உள்ளீடுகளை சில விதிகளுக்கு எதிராக சரிபார்க்க வேண்டியிருக்கும் போது, சாதாரண அணுகுமுறை போதுமானதாக இருக்காது. இங்குதான் நாம் நிலையான லைப்ரரிக்கு அப்பால், கணினி அறிவியல் அல்காரிதம்கள் மற்றும் தரவுக் கட்டமைப்புகளின் உலகிற்குள் ஆழமாகச் சென்று நமது சொந்த உகந்த ஸ்ட்ரிங் செயலாக்க இன்ஜினை உருவாக்க வேண்டும்.
இந்த விரிவான வழிகாட்டி உங்களை அடிப்படை, முரட்டுத்தனமான முறைகளிலிருந்து அகோ-கொராசிக் போன்ற மேம்பட்ட, உயர்-செயல்திறன் அல்காரிதம்களுக்கு ஒரு பயணத்திற்கு அழைத்துச் செல்லும். சில அணுகுமுறைகள் ஏன் அழுத்தத்தின் கீழ் தோல்வியடைகின்றன என்பதையும், மற்றவை, புத்திசாலித்தனமான முன்-கணக்கீடு மற்றும் நிலை மேலாண்மை மூலம், நேரியல்-நேர செயல்திறனை எவ்வாறு அடைகின்றன என்பதையும் நாம் ஆராய்வோம். இறுதியில், நீங்கள் கோட்பாட்டைப் புரிந்துகொள்வது மட்டுமல்லாமல், ஜாவாஸ்கிரிப்டில் ஒரு நடைமுறை, உயர்-செயல்திறன், பல-பேட்டர்ன் பொருத்துதல் இன்ஜினை புதிதாக உருவாக்கவும் தயாராகிவிடுவீர்கள்.
ஸ்ட்ரிங் பொருத்தத்தின் பரவலான தன்மை
குறியீட்டிற்குள் நுழைவதற்கு முன், திறமையான ஸ்ட்ரிங் பொருத்தத்தை நம்பியிருக்கும் பயன்பாடுகளின் பரந்த அளவைப் பாராட்டுவது அவசியம். இந்த பயன்பாட்டு நிகழ்வுகளை அங்கீகரிப்பது மேம்படுத்தலின் முக்கியத்துவத்தை சூழல்படுத்த உதவுகிறது.
- வலைப் பயன்பாட்டு ஃபயர்வால்கள் (WAFs): பாதுகாப்பு அமைப்புகள் உள்வரும் HTTP கோரிக்கைகளை ஆயிரக்கணக்கான அறியப்பட்ட தாக்குதல் கையொப்பங்களுக்காக (எ.கா., SQL இன்ஜெக்ஷன், கிராஸ்-சைட் ஸ்கிரிப்டிங் பேட்டர்ன்கள்) ஸ்கேன் செய்கின்றன. பயனர் கோரிக்கைகளை தாமதப்படுத்தாமல் இருக்க இது மைக்ரோ விநாடிகளில் நடக்க வேண்டும்.
- டெக்ஸ்ட் எடிட்டர்கள் & IDEகள்: சிண்டாக்ஸ் ஹைலைட்டிங், புத்திசாலித்தனமான தேடல், மற்றும் 'அனைத்து நிகழ்வுகளையும் கண்டுபிடி' போன்ற அம்சங்கள், பெரிய மூலக் குறியீடு கோப்புகளில் பல முக்கிய வார்த்தைகளையும் பேட்டர்ன்களையும் விரைவாக அடையாளம் காண்பதை நம்பியுள்ளன.
- உள்ளடக்க வடிகட்டுதல் & மிதப்படுத்தல்: சமூக ஊடக தளங்கள் மற்றும் மன்றங்கள், பயனர் உருவாக்கிய உள்ளடக்கத்தை பொருத்தமற்ற சொற்கள் அல்லது சொற்றொடர்களின் ஒரு பெரிய அகராதிக்கு எதிராக நிகழ்நேரத்தில் ஸ்கேன் செய்கின்றன.
- உயிரியல் தகவல்நுட்பம் (Bioinformatics): விஞ்ஞானிகள் மிகப்பெரிய டிஎன்ஏ இழைகளில் (உரை) குறிப்பிட்ட மரபணு வரிசைகளை (பேட்டர்ன்கள்) தேடுகின்றனர். இந்த அல்காரிதம்களின் செயல்திறன் மரபணு ஆராய்ச்சிக்கு மிக முக்கியமானது.
- தரவு இழப்பு தடுப்பு (DLP) அமைப்புகள்: இந்த கருவிகள் வெளிச்செல்லும் மின்னஞ்சல்கள் மற்றும் கோப்புகளை கிரெடிட் கார்டு எண்கள் அல்லது உள் திட்டக் குறியீட்டுப் பெயர்கள் போன்ற முக்கியமான தகவல் பேட்டர்ன்களுக்காக ஸ்கேன் செய்து தரவு மீறல்களைத் தடுக்கின்றன.
- தேடுபொறிகள்: அவற்றின் மையத்தில், தேடுபொறிகள் அதிநவீன பேட்டர்ன் பொருத்துபவர்களாகும், அவை வலையை அட்டவணைப்படுத்தி, பயனர் வினவிய பேட்டர்ன்களைக் கொண்ட ஆவணங்களைக் கண்டறிகின்றன.
இந்த ஒவ்வொரு சூழ்நிலையிலும், செயல்திறன் ஒரு ஆடம்பரம் அல்ல; அது ஒரு முக்கிய தேவை. ஒரு மெதுவான அல்காரிதம் பாதுகாப்பு பாதிப்புகள், மோசமான பயனர் அனுபவம் அல்லது தடைசெய்யும் கணினிச் செலவுகளுக்கு வழிவகுக்கும்.
எளிமையான அணுகுமுறை மற்றும் அதன் தவிர்க்க முடியாத தடை
ஒரு உரையில் ஒரு பேட்டர்னைக் கண்டுபிடிக்க மிகவும் நேரடியான வழியுடன் ஆரம்பிக்கலாம்: முரட்டுத்தனமான முறை. தர்க்கம் எளிமையானது: பேட்டர்னை உரையின் மீது ஒரு நேரத்தில் ஒரு எழுத்தாக நகர்த்தி, ஒவ்வொரு நிலையிலும், பேட்டர்ன் தொடர்புடைய உரைப் பகுதிக்கு பொருந்துகிறதா என்று சரிபார்க்கவும்.
ஒரு நேரடி செயலாக்க முறை
ஒரு பெரிய உரைக்குள் ஒரு ஒற்றை பேட்டர்னின் அனைத்து நிகழ்வுகளையும் நாம் கண்டுபிடிக்க விரும்புகிறோம் என்று கற்பனை செய்து பாருங்கள்.
function naiveSearch(text, pattern) {
const textLength = text.length;
const patternLength = pattern.length;
const occurrences = [];
if (patternLength === 0) return [];
for (let i = 0; i <= textLength - patternLength; i++) {
let match = true;
for (let j = 0; j < patternLength; j++) {
if (text[i + j] !== pattern[j]) {
match = false;
break;
}
}
if (match) {
occurrences.push(i);
}
}
return occurrences;
}
const text = "abracadabra";
const pattern = "abra";
console.log(naiveSearch(text, pattern)); // Output: [0, 7]
அது ஏன் தவறுகிறது: நேர சிக்கல் பகுப்பாய்வு
வெளிப்புற லூப் தோராயமாக N முறை இயங்குகிறது (இங்கு N என்பது உரையின் நீளம்), மற்றும் உள் லூப் M முறை இயங்குகிறது (இங்கு M என்பது பேட்டர்னின் நீளம்). இது அல்காரிதத்திற்கு O(N * M) நேர சிக்கலைக் கொடுக்கிறது. சிறிய ஸ்ட்ரிங்களுக்கு, இது முற்றிலும் சரி. ஆனால் 10MB உரை (≈10,000,000 எழுத்துக்கள்) மற்றும் 100-எழுத்து பேட்டர்னைக் கவனியுங்கள். ஒப்பீடுகளின் எண்ணிக்கை பில்லியன்களில் இருக்கலாம்.
இப்போது, நாம் K வெவ்வேறு பேட்டர்ன்களைத் தேட வேண்டியிருந்தால் என்ன செய்வது? எளிய நீட்டிப்பு, நமது பேட்டர்ன்கள் வழியாக ஒரு லூப் செய்து, ஒவ்வொன்றிற்கும் எளிய தேடலை இயக்குவதாகும், இது O(K * N * M) என்ற பயங்கரமான சிக்கலுக்கு வழிவகுக்கும். எந்தவொரு தீவிரமான பயன்பாட்டிற்கும் இந்த அணுகுமுறை முற்றிலும் உடைந்து போகும் இடம் இது.
முரட்டுத்தனமான முறையின் முக்கிய திறமையின்மை என்னவென்றால், அது பொருந்தாமைகளிலிருந்து எதையும் கற்றுக்கொள்வதில்லை. ஒரு பொருந்தாமை ஏற்படும் போது, அது பேட்டர்னை ஒரு நிலை மட்டுமே நகர்த்தி, மீண்டும் ஒப்பீட்டைத் தொடங்குகிறது, பொருந்தாமையிலிருந்து கிடைத்த தகவல் நம்மை இன்னும் அதிகமாக நகர்த்தச் சொல்லியிருந்தாலும் கூட.
அடிப்படை மேம்படுத்தல் உத்திகள்: கடினமாக அல்ல, புத்திசாலித்தனமாக சிந்திப்பது
எளிய அணுகுமுறையின் வரம்புகளைக் கடக்க, கணினி விஞ்ஞானிகள் புத்திசாலித்தனமான அல்காரிதம்களை உருவாக்கியுள்ளனர், அவை தேடல் கட்டத்தை நம்பமுடியாத அளவிற்கு வேகமாக மாற்ற முன்-கணக்கீட்டைப் பயன்படுத்துகின்றன. அவை முதலில் பேட்டர்ன்(கள்) பற்றிய தகவல்களைச் சேகரித்து, பின்னர் அந்தத் தகவலைப் பயன்படுத்தி தேடலின் போது உரையின் பெரிய பகுதிகளைத் தவிர்க்கின்றன.
ஒற்றை பேட்டர்ன் பொருத்தம்: போயர்-மூர் மற்றும் KMP
ஒரு ஒற்றை பேட்டர்னைத் தேடும்போது, போயர்-மூர் மற்றும் நத்-மோரிஸ்-பிராட் (KMP) ஆகிய இரண்டு உன்னதமான அல்காரிதம்கள் ஆதிக்கம் செலுத்துகின்றன.
- போயர்-மூர் அல்காரிதம்: இது நடைமுறை ஸ்ட்ரிங் தேடலுக்கான அளவுகோலாக அடிக்கடி கருதப்படுகிறது. அதன் புத்திசாலித்தனம் இரண்டு ஹியூரிஸ்டிக்ஸில் உள்ளது. முதலில், இது பேட்டர்னை இடமிருந்து வலமாகப் பொருத்துவதற்குப் பதிலாக வலமிருந்து இடமாகப் பொருத்துகிறது. ஒரு பொருந்தாமை ஏற்படும் போது, அது முன்-கணக்கிடப்பட்ட 'மோசமான எழுத்து அட்டவணையை'ப் பயன்படுத்தி அதிகபட்ச பாதுகாப்பான முன்னோக்கிய நகர்வை தீர்மானிக்கிறது. எடுத்துக்காட்டாக, நாம் "EXAMPLE" ஐ உரைக்கு எதிராகப் பொருத்தி, ஒரு பொருந்தாமையைக் கண்டறிந்து, உரையில் உள்ள எழுத்து 'Z' ஆக இருந்தால், 'Z' "EXAMPLE" இல் தோன்றாது என்பதை நாம் அறிவோம், எனவே முழு பேட்டர்னையும் இந்த புள்ளிக்கு அப்பால் நகர்த்தலாம். இது நடைமுறையில் பெரும்பாலும் துணை-நேரியல் செயல்திறனில் விளைகிறது.
- நத்-மோரிஸ்-பிராட் (KMP) அல்காரிதம்: KMP இன் புதுமை ஒரு முன்-கணக்கிடப்பட்ட 'முன்னொட்டுச் செயல்பாடு' அல்லது நீண்ட சரியான முன்னொட்டு பின்னொட்டு (LPS) வரிசையாகும். இந்த வரிசை, பேட்டர்னின் எந்தவொரு முன்னொட்டுக்கும், ஒரு பின்னொட்டாகவும் இருக்கும் மிக நீளமான சரியான முன்னொட்டின் நீளத்தை நமக்குச் சொல்கிறது. இந்தத் தகவல், ஒரு பொருந்தாமைக்குப் பிறகு அல்காரிதம் தேவையற்ற ஒப்பீடுகளைத் தவிர்க்க அனுமதிக்கிறது. ஒரு பொருந்தாமை ஏற்படும் போது, ஒன்றாக நகர்த்துவதற்குப் பதிலாக, அது LPS மதிப்பின் அடிப்படையில் பேட்டர்னை நகர்த்துகிறது, திறம்பட முன்பு பொருந்திய பகுதியிலிருந்து தகவலை மீண்டும் பயன்படுத்துகிறது.
இவை ஒற்றை-பேட்டர்ன் தேடல்களுக்கு கவர்ச்சிகரமானதாகவும் சக்திவாய்ந்ததாகவும் இருந்தாலும், நமது குறிக்கோள் பல பேட்டர்ன்களை அதிகபட்ச செயல்திறனுடன் கையாளும் ஒரு இன்ஜினை உருவாக்குவதாகும். அதற்கு, நமக்கு வேறு வகையான ஒரு மிருகம் தேவை.
பல-பேட்டர்ன் பொருத்தம்: அகோ-கொராசிக் அல்காரிதம்
ஆல்ஃபிரட் அகோ மற்றும் மார்கரெட் கொராசிக் ஆகியோரால் உருவாக்கப்பட்ட அகோ-கொராசிக் அல்காரிதம், ஒரு உரையில் பல பேட்டர்ன்களைக் கண்டுபிடிப்பதில் மறுக்கமுடியாத சாம்பியன் ஆகும். இது யூனிக்ஸ் கட்டளையான `fgrep` போன்ற கருவிகளின் அடிப்படையிலான அல்காரிதம் ஆகும். அதன் மந்திரம் என்னவென்றால், அதன் தேடல் நேரம் O(N + L + Z) ஆகும், இங்கு N என்பது உரையின் நீளம், L என்பது அனைத்து பேட்டர்ன்களின் மொத்த நீளம், மற்றும் Z என்பது பொருத்தங்களின் எண்ணிக்கை. தேடல் சிக்கலில் பேட்டர்ன்களின் எண்ணிக்கை (K) ஒரு பெருக்கி அல்ல என்பதை கவனியுங்கள்! இது ஒரு மகத்தான முன்னேற்றம்.
இது இதை எப்படி அடைகிறது? இரண்டு முக்கிய தரவுக் கட்டமைப்புகளை இணைப்பதன் மூலம்:
- ஒரு டிரை (முன்னொட்டு மரம்): இது முதலில் அனைத்து பேட்டர்ன்களையும் (நமது முக்கிய வார்த்தைகளின் அகராதி) கொண்ட ஒரு டிரையை உருவாக்குகிறது.
- தோல்வி இணைப்புகள்: பின்னர் அது டிரையை 'தோல்வி இணைப்புகளுடன்' பெருக்குகிறது. ஒரு முனைக்கான தோல்வி இணைப்பு, அந்த முனையால் குறிப்பிடப்படும் ஸ்ட்ரிங்கின் மிக நீளமான சரியான பின்னொட்டுக்கு சுட்டிக்காட்டுகிறது, இது டிரையில் உள்ள சில பேட்டர்னின் முன்னொட்டாகவும் உள்ளது.
இந்த ஒருங்கிணைந்த கட்டமைப்பு ஒரு வரையறுக்கப்பட்ட ஆட்டோமேட்டனை உருவாக்குகிறது. தேடலின் போது, நாம் உரையை ஒரு நேரத்தில் ஒரு எழுத்தாக செயலாக்குகிறோம், ஆட்டோமேட்டன் வழியாக நகர்கிறோம். நாம் ஒரு எழுத்து இணைப்பைப் பின்பற்ற முடியாவிட்டால், ஒரு தோல்வி இணைப்பைப் பின்பற்றுகிறோம். இது உள்ளீட்டு உரையில் எழுத்துக்களை மீண்டும் ஸ்கேன் செய்யாமல் தேடலைத் தொடர அனுமதிக்கிறது.
ரெகுலர் எக்ஸ்பிரஷன்கள் பற்றிய ஒரு குறிப்பு
ஜாவாஸ்கிரிப்டின் `RegExp` இன்ஜின் நம்பமுடியாத அளவிற்கு சக்திவாய்ந்தது மற்றும் அதிக அளவில் மேம்படுத்தப்பட்டது, இது பெரும்பாலும் நேட்டிவ் C++ இல் செயல்படுத்தப்படுகிறது. பல பணிகளுக்கு, நன்கு எழுதப்பட்ட ரெஜெக்ஸ் சிறந்த கருவியாகும். இருப்பினும், இது ஒரு செயல்திறன் பொறியாகவும் இருக்கலாம்.
- பேரழிவு பின்வாங்கல் (Catastrophic Backtracking): மோசமாக கட்டமைக்கப்பட்ட ரெஜெக்ஸ்கள், உள்ளமைக்கப்பட்ட குவாண்டிஃபையர்கள் மற்றும் மாற்றுகளுடன் (எ.கா.,
(a|b|c*)*
) சில உள்ளீடுகளில் அதிவேக இயக்க நேரங்களுக்கு வழிவகுக்கும். இது உங்கள் பயன்பாடு அல்லது சேவையகத்தை முடக்கக்கூடும். - மேலதிக செலவு (Overhead): ஒரு சிக்கலான ரெஜெக்ஸைத் தொகுப்பதற்கு ஆரம்ப செலவு உள்ளது. ஒரு பெரிய தொகுப்பு எளிய, நிலையான ஸ்ட்ரிங்குகளைக் கண்டுபிடிப்பதற்கு, ஒரு ரெஜெக்ஸ் இன்ஜினின் மேலதிக செலவு அகோ-கொராசிக் போன்ற ஒரு சிறப்பு அல்காரிதத்தை விட அதிகமாக இருக்கலாம்.
மேம்படுத்தல் குறிப்பு: பல முக்கிய வார்த்தைகளுக்கு ரெஜெக்ஸைப் பயன்படுத்தும் போது, அவற்றை திறமையாக இணைக்கவும். str.match(/cat|)|str.match(/dog/)|str.match(/bird/)
என்பதற்குப் பதிலாக, ஒரு ஒற்றை ரெஜெக்ஸைப் பயன்படுத்தவும்: str.match(/cat|dog|bird/g)
. இன்ஜின் இந்த ஒற்றை பத்தியை மிகச் சிறப்பாக மேம்படுத்த முடியும்.
நமது அகோ-கொராசிக் இன்ஜினை உருவாக்குதல்: ஒரு படிப்படியான வழிகாட்டி
வாருங்கள், இந்த சக்திவாய்ந்த இன்ஜினை ஜாவாஸ்கிரிப்டில் உருவாக்குவோம். நாம் இதை மூன்று கட்டங்களில் செய்வோம்: அடிப்படை டிரையை உருவாக்குதல், தோல்வி இணைப்புகளைச் சேர்ப்பது, மற்றும் இறுதியாக, தேடல் செயல்பாட்டைச் செயல்படுத்துவது.
படி 1: டிரை தரவு கட்டமைப்பின் அடித்தளம்
ஒரு டிரை என்பது ஒரு மரம் போன்ற தரவுக் கட்டமைப்பாகும், அங்கு ஒவ்வொரு முனையும் ஒரு எழுத்தைக் குறிக்கிறது. ரூட்டிலிருந்து ஒரு முனைக்கான பாதைகள் முன்னொட்டுகளைக் குறிக்கின்றன. ஒரு முழுமையான பேட்டர்னின் முடிவைக் குறிக்கும் முனைகளில் நாம் ஒரு `output` வரிசையைச் சேர்ப்போம்.
class TrieNode {
constructor() {
this.children = {}; // Maps characters to other TrieNodes
this.isEndOfWord = false;
this.output = []; // Stores patterns that end at this node
this.failureLink = null; // To be added later
}
}
class AhoCorasickEngine {
constructor(patterns) {
this.root = new TrieNode();
this.buildTrie(patterns);
this.buildFailureLinks();
}
/**
* Builds the basic Trie from a list of patterns.
*/
buildTrie(patterns) {
for (const pattern of patterns) {
if (typeof pattern !== 'string' || pattern.length === 0) continue;
let currentNode = this.root;
for (const char of pattern) {
if (!currentNode.children[char]) {
currentNode.children[char] = new TrieNode();
}
currentNode = currentNode.children[char];
}
currentNode.isEndOfWord = true;
currentNode.output.push(pattern);
}
}
// ... buildFailureLinks and search methods to come
}
படி 2: தோல்வி இணைப்புகளின் வலையைப் பின்னுதல்
இது மிக முக்கியமான மற்றும் கருத்தியல் ரீதியாக சிக்கலான பகுதியாகும். ஒவ்வொரு முனைக்கும் தோல்வி இணைப்புகளை உருவாக்க, ரூட்டிலிருந்து தொடங்கி ஒரு அகல-முதல் தேடலை (BFS) பயன்படுத்துவோம். ரூட்டின் தோல்வி இணைப்பு தன்னையே சுட்டிக்காட்டுகிறது. வேறு எந்த முனைக்கும், அதன் தோல்வி இணைப்பு அதன் பெற்றோர் தோல்வி இணைப்பைக் கடந்து, தற்போதைய முனையின் எழுத்துக்கான பாதை உள்ளதா என்று பார்ப்பதன் மூலம் கண்டறியப்படுகிறது.
// Add this method inside the AhoCorasickEngine class
buildFailureLinks() {
const queue = [];
this.root.failureLink = this.root; // The root's failure link points to itself
// Start BFS with the children of the root
for (const char in this.root.children) {
const node = this.root.children[char];
node.failureLink = this.root;
queue.push(node);
}
while (queue.length > 0) {
const currentNode = queue.shift();
for (const char in currentNode.children) {
const nextNode = currentNode.children[char];
let failureNode = currentNode.failureLink;
// Traverse failure links until we find a node with a transition for the current character,
// or we reach the root.
while (failureNode.children[char] === undefined && failureNode !== this.root) {
failureNode = failureNode.failureLink;
}
if (failureNode.children[char]) {
nextNode.failureLink = failureNode.children[char];
} else {
nextNode.failureLink = this.root;
}
// Also, merge the output of the failure link node with the current node's output.
// This ensures we find patterns that are suffixes of other patterns (e.g., finding "he" in "she").
nextNode.output.push(...nextNode.failureLink.output);
queue.push(nextNode);
}
}
}
படி 3: அதிவேக தேடல் செயல்பாடு
முழுமையாக கட்டமைக்கப்பட்ட நமது ஆட்டோமேட்டன் மூலம், தேடல் நேர்த்தியாகவும் திறமையாகவும் மாறுகிறது. நாம் உள்ளீட்டு உரையை எழுத்து வாரியாகக் கடந்து, நமது டிரை வழியாக நகர்கிறோம். ஒரு நேரடி பாதை இல்லை என்றால், நாம் ஒரு பொருத்தத்தைக் கண்டுபிடிக்கும் வரை அல்லது ரூட்டிற்குத் திரும்பும் வரை தோல்வி இணைப்பைப் பின்பற்றுகிறோம். ஒவ்வொரு படியிலும், தற்போதைய முனையின் `output` வரிசையை ஏதேனும் பொருத்தங்களுக்கு சரிபார்க்கிறோம்.
// Add this method inside the AhoCorasickEngine class
search(text) {
let currentNode = this.root;
const results = [];
for (let i = 0; i < text.length; i++) {
const char = text[i];
while (currentNode.children[char] === undefined && currentNode !== this.root) {
currentNode = currentNode.failureLink;
}
if (currentNode.children[char]) {
currentNode = currentNode.children[char];
}
// If we are at the root and there's no path for the current char, we stay at the root.
if (currentNode.output.length > 0) {
for (const pattern of currentNode.output) {
results.push({
pattern: pattern,
index: i - pattern.length + 1
});
}
}
}
return results;
}
அனைத்தையும் ஒன்றிணைத்தல்: ஒரு முழுமையான எடுத்துக்காட்டு
// (Include the full TrieNode and AhoCorasickEngine class definitions from above)
const patterns = ["he", "she", "his", "hers"];
const text = "ushers";
const engine = new AhoCorasickEngine(patterns);
const matches = engine.search(text);
console.log(matches);
// Expected Output:
// [
// { pattern: 'he', index: 2 },
// { pattern: 'she', index: 1 },
// { pattern: 'hers', index: 2 }
// ]
நமது இன்ஜின் "ushers" இன் இன்டெக்ஸ் 5 இல் முடிவடையும் "he" மற்றும் "hers" ஐயும், இன்டெக்ஸ் 3 இல் முடிவடையும் "she" ஐயும் சரியாகக் கண்டறிந்தது என்பதை கவனியுங்கள். இது தோல்வி இணைப்புகள் மற்றும் ஒன்றிணைக்கப்பட்ட வெளியீடுகளின் சக்தியை நிரூபிக்கிறது.
அல்காரிதத்திற்கு அப்பால்: இன்ஜின்-நிலை மற்றும் சுற்றுச்சூழல் மேம்படுத்தல்கள்
ஒரு சிறந்த அல்காரிதம் நமது இன்ஜினின் இதயமாகும், ஆனால் V8 (Chrome மற்றும் Node.js இல்) போன்ற ஒரு ஜாவாஸ்கிரிப்ட் சூழலில் உச்ச செயல்திறனுக்காக, நாம் மேலும் மேம்படுத்தல்களைக் கருத்தில் கொள்ளலாம்.
- முன்-கணக்கீடு முக்கியம்: அகோ-கொராசிக் ஆட்டோமேட்டனை உருவாக்குவதற்கான செலவு ஒரு முறை மட்டுமே செலுத்தப்படுகிறது. உங்கள் பேட்டர்ன்களின் தொகுப்பு நிலையானதாக இருந்தால் (ஒரு WAF விதிமுறைத் தொகுப்பு அல்லது ஒரு அவதூறு வடிப்பான் போன்றவை), இன்ஜினை ஒரு முறை உருவாக்கி, அதை மில்லியன் கணக்கான தேடல்களுக்கு மீண்டும் பயன்படுத்தவும். இது அமைப்புச் செலவை பூஜ்ஜியத்திற்கு அருகில் குறைக்கிறது.
- ஸ்ட்ரிங் பிரதிநிதித்துவம்: ஜாவாஸ்கிரிப்ட் இன்ஜின்கள் அதிக அளவில் மேம்படுத்தப்பட்ட உள் ஸ்ட்ரிங் பிரதிநிதித்துவங்களைக் கொண்டுள்ளன. ஒரு இறுக்கமான லூப்பில் பல சிறிய துணை ஸ்ட்ரிங்குகளை உருவாக்குவதைத் தவிர்க்கவும் (எ.கா.,
text.substring()
ஐ மீண்டும் மீண்டும் பயன்படுத்துதல்). குறியீட்டு எண் மூலம் எழுத்துக்களை அணுகுவது (text[i]
) பொதுவாக மிக வேகமாக இருக்கும். - நினைவக மேலாண்மை: மிகவும் பெரிய பேட்டர்ன்களின் தொகுப்பிற்கு, டிரை குறிப்பிடத்தக்க நினைவகத்தை நுகரக்கூடும். இதைக் கவனத்தில் கொள்ளுங்கள். இதுபோன்ற சந்தர்ப்பங்களில், ரோலிங் ஹாஷ்களுடன் கூடிய ராபின்-கார்ப் போன்ற பிற அல்காரிதம்கள் வேகம் மற்றும் நினைவகத்திற்கு இடையில் வேறுபட்ட வர்த்தகத்தை வழங்கக்கூடும்.
- வெப்அசெம்பிளி (WASM): மிகவும் தேவைப்படும், செயல்திறன்-முக்கியமான பணிகளுக்கு, நீங்கள் மைய பொருத்துதல் தர்க்கத்தை ரஸ்ட் அல்லது C++ போன்ற ஒரு மொழியில் செயல்படுத்தி அதை வெப்அசெம்பிளிக்கு தொகுக்கலாம். இது உங்கள் குறியீட்டின் சூடான பாதைக்கு ஜாவாஸ்கிரிப்ட் இன்டர்பிரெட்டர் மற்றும் JIT கம்பைலரைத் தவிர்த்து, கிட்டத்தட்ட நேட்டிவ் செயல்திறனை உங்களுக்கு வழங்குகிறது. இது ஒரு மேம்பட்ட நுட்பம் ஆனால் இறுதி வேகத்தை வழங்குகிறது.
செயல்திறன் அளவீடு: நிரூபிக்கவும், அனுமானிக்க வேண்டாம்
நீங்கள் அளவிட முடியாததை உங்களால் மேம்படுத்த முடியாது. நமது தனிப்பயன் இன்ஜின் உண்மையில் எளிய மாற்றுகளை விட வேகமானது என்பதை சரிபார்க்க ஒரு சரியான செயல்திறன் அளவீட்டை அமைப்பது முக்கியம்.
ஒரு கற்பனையான சோதனை வழக்கை வடிவமைப்போம்:
- உரை: ஒரு 5MB உரை கோப்பு (எ.கா., ஒரு நாவல்).
- பேட்டர்ன்கள்: 500 பொதுவான ஆங்கில வார்த்தைகளின் ஒரு வரிசை.
நாம் நான்கு முறைகளை ஒப்பிடுவோம்:
indexOf
உடன் எளிய லூப்: அனைத்து 500 பேட்டர்ன்களுக்கும் லூப் செய்து, ஒவ்வொன்றிற்கும்text.indexOf(pattern)
ஐ அழைக்கவும்.- ஒற்றை தொகுக்கப்பட்ட RegExp: அனைத்து பேட்டர்ன்களையும்
/word1|word2|...|word500/g
போன்ற ஒரு ரெஜெக்ஸில் இணைத்து,text.match()
ஐ இயக்கவும். - நமது அகோ-கொராசிக் இன்ஜின்: இன்ஜினை ஒரு முறை உருவாக்கி, பின்னர் தேடலை இயக்கவும்.
- எளிய முரட்டுத்தனமான முறை: O(K * N * M) அணுகுமுறை.
ஒரு எளிய செயல்திறன் அளவீட்டு ஸ்கிரிப்ட் இதுபோல இருக்கலாம்:
console.time("Aho-Corasick Search");
const matches = engine.search(largeText);
console.timeEnd("Aho-Corasick Search");
// Repeat for other methods...
எதிர்பார்க்கப்படும் முடிவுகள் (விளக்கத்திற்கு):
- எளிய முரட்டுத்தனமான முறை: > 10,000 ms (அல்லது அளவிட முடியாத அளவிற்கு மெதுவாக)
indexOf
உடன் எளிய லூப்: ~1500 ms- ஒற்றை தொகுக்கப்பட்ட RegExp: ~300 ms
- அகோ-கொராசிக் இன்ஜின்: ~50 ms
முடிவுகள் கட்டிடக்கலை நன்மையை தெளிவாகக் காட்டுகின்றன. அதிக அளவில் மேம்படுத்தப்பட்ட நேட்டிவ் RegExp இன்ஜின் கைமுறை லூப்களை விட ஒரு பெரிய முன்னேற்றமாக இருந்தாலும், இந்த சரியான சிக்கலுக்காக பிரத்யேகமாக வடிவமைக்கப்பட்ட அகோ-கொராசிக் அல்காரிதம், மற்றொரு மடங்கு வேக அதிகரிப்பை வழங்குகிறது.
முடிவுரை: வேலைக்கு சரியான கருவியைத் தேர்ந்தெடுத்தல்
ஸ்ட்ரிங் பேட்டர்ன் மேம்படுத்தலுக்கான பயணம் மென்பொருள் பொறியியலின் ஒரு அடிப்படை உண்மையை வெளிப்படுத்துகிறது: உயர்-நிலை சுருக்கங்கள் மற்றும் உள்ளமைக்கப்பட்ட செயல்பாடுகள் உற்பத்தித்திறனுக்கு விலைமதிப்பற்றவை என்றாலும், அடிப்படை கொள்கைகளைப் பற்றிய ஆழமான புரிதல்தான் உண்மையான உயர்-செயல்திறன் அமைப்புகளை உருவாக்க நமக்கு உதவுகிறது.
நாம் கற்றுக்கொண்டவை:
- எளிய அணுகுமுறை எளிமையானது ஆனால் மோசமாக அளவிடக்கூடியது, இது தேவைப்படும் பயன்பாடுகளுக்குப் பொருத்தமற்றது.
- ஜாவாஸ்கிரிப்டின் `RegExp` இன்ஜின் ஒரு சக்திவாய்ந்த மற்றும் வேகமான கருவியாகும், ஆனால் செயல்திறன் சிக்கல்களைத் தவிர்க்க கவனமான பேட்டர்ன் கட்டுமானம் தேவைப்படுகிறது மற்றும் ஆயிரக்கணக்கான நிலையான ஸ்ட்ரிங்குகளைப் பொருத்துவதற்கு இது உகந்த தேர்வாக இருக்காது.
- அகோ-கொராசிக் போன்ற சிறப்பு அல்காரிதம்கள், நேரியல் தேடல் நேரத்தை அடைய புத்திசாலித்தனமான முன்-கணக்கீட்டை (டிரைகள் மற்றும் தோல்வி இணைப்புகள்) பயன்படுத்துவதன் மூலம் பல-பேட்டர்ன் பொருத்தத்தில் செயல்திறனில் குறிப்பிடத்தக்க பாய்ச்சலை வழங்குகின்றன.
ஒரு தனிப்பயன் ஸ்ட்ரிங் பொருத்துதல் இன்ஜினை உருவாக்குவது ஒவ்வொரு திட்டத்திற்கும் ஒரு பணி அல்ல. ஆனால் நீங்கள் உரை செயலாக்கத்தில் ஒரு செயல்திறன் தடையை எதிர்கொள்ளும்போது, அது ஒரு Node.js பின்தளத்திலோ, ஒரு கிளையன்ட் பக்க தேடல் அம்சத்திலோ, அல்லது ஒரு பாதுகாப்பு பகுப்பாய்வுக் கருவியிலோ இருந்தாலும், இப்போது உங்களுக்கு நிலையான லைப்ரரிக்கு அப்பால் பார்க்க அறிவு உள்ளது. சரியான அல்காரிதம் மற்றும் தரவுக் கட்டமைப்பைத் தேர்ந்தெடுப்பதன் மூலம், நீங்கள் ஒரு மெதுவான, வளம்-செறிந்த செயல்முறையை ஒரு மெலிதான, திறமையான மற்றும் அளவிடக்கூடிய தீர்வாக மாற்றலாம்.