PHP में एक स्ट्रिंग में प्रत्येक पंक्ति पर Iterate


130

मेरे पास एक ऐसा फॉर्म है जो उपयोगकर्ता को टेक्स्ट फाइल अपलोड करने या फाइल के कंटेंट को कॉपीरैस में कॉपी / पेस्ट करने की अनुमति देता है। मैं आसानी से दोनों के बीच अंतर कर सकता हूं और जो भी वे एक स्ट्रिंग चर में प्रवेश करते हैं, वहां डाल देंगे, लेकिन मैं वहां से कहां जाऊंगा?

मुझे स्ट्रिंग की प्रत्येक पंक्ति पर पुनरावृति करने की आवश्यकता है (अधिमानतः अलग-अलग मशीनों पर नईलाइन्स के बारे में चिंता न करें), सुनिश्चित करें कि इसमें ठीक एक टोकन है (कोई रिक्त स्थान, टैब, अल्पविराम, आदि), डेटा को साफ करें, फिर एक SQL क्वेरी उत्पन्न करें। सभी पंक्तियों के आधार पर।

मैं काफी अच्छा प्रोग्रामर हूं, इसलिए मैं सामान्य विचार जानता हूं कि इसे कैसे करना है, लेकिन जब से मैंने PHP के साथ काम किया है, तब तक यह बहुत लंबा हो चुका है कि मुझे लगता है कि मैं गलत चीजों को खोज रहा हूं और इस तरह बेकार जानकारी आ रही है। मुख्य समस्या यह है कि मैं स्ट्रिंग लाइन-बाय-लाइन की सामग्री को पढ़ना चाहता हूं। यदि यह एक फ़ाइल होती, तो यह आसान होता।

मैं ज्यादातर उपयोगी PHP कार्यों की तलाश कर रहा हूं, यह कैसे करना है के लिए एल्गोरिथ्म नहीं। कोई सुझाव?


हो सकता है कि आप सबसे पहले नईलाइन्स को सामान्य करना चाहें। यह विधि github.com/delight-im/PHP-Str (MIT लाइसेंस के तहत पुस्तकालय) के s($myString)->normalizeLineEndings()साथ उपलब्ध है जिसमें बहुत से अन्य उपयोगी स्ट्रिंग हेल्पर्स हैं। आप स्रोत कोड पर एक नज़र रखना चाहते हैं।
'25

जवाबों:


190

preg_split पाठ वाले चर, और दिए गए सरणी पर पुनरावृति:

foreach(preg_split("/((\r?\n)|(\r\n?))/", $subject) as $line){
    // do stuff with $line
} 

क्या यह \ N \ r के अलावा ^ M को हैंडल करेगा?
फांगियो सेप

अगर एक वेरिएबल के अंदर रखने पर ascii कैरिज रिटर्न to \ r में परिवर्तित हो जाता है तो मुझे यकीन नहीं है। यदि आप हमेशा एक विभाजन () / एक्सलोप () के बजाय एस्की मूल्य के साथ उपयोग नहीं कर सकते हैं - ch (13)
किरिल

12
एक बेहतर regexp है /((\r?\n)|(\r\n?))/
फेलिक्स सपरेली 5

3
Unix LF (\ n), MacOS <9 CR (\ r), विंडोज CR + LF (\ r \ n) और दुर्लभ LF + CR (\ n \ r) का मिलान करने के लिए यह होना चाहिए:/((\r?\n)|(\n?\r))/
देव की प्रतीक्षा ...

2
यह बहु-बाइट डेटा के लिए विनाशकारी रूप से बम बनाने की संभावना है।
पगडियारियो

158

मैं एक बहुत तेज़ (और मेमोरी कुशल) विकल्प का प्रस्ताव करना चाहूंगा : strtokइसके बजाय preg_split

$separator = "\r\n";
$line = strtok($subject, $separator);

while ($line !== false) {
    # do something with $line
    $line = strtok( $separator );
}

प्रदर्शन का परीक्षण करते हुए, मैंने 17 हजार लाइनों के साथ एक परीक्षण फ़ाइल पर 100 बार पुनरावृत्त preg_splitकिया : 27.7 सेकंड का समय strtokलिया , जबकि 1.4 सेकंड का समय लिया।

ध्यान दें कि हालांकि, $separatorपरिभाषित किया गया है "\r\n", strtokया तो चरित्र पर अलग होगा - और PHP4.1.0 के रूप में, खाली लाइनों / टोकन को छोड़ दें।

स्ट्रैटोक मैनुअल प्रविष्टि देखें: http://php.net/strtok


21
बड़ी लाइन सेट के साथ काम करते समय प्रदर्शन के विचारों के लिए +1
CodeAngry

4
हालांकि यह फ़ंक्शन एपीआई कुल गड़बड़ है (विभिन्न मापदंडों के साथ कॉल) यह सबसे अच्छा समाधान है। न तो prey_splitहै और न ही explodeसंरचित स्ट्रिंग टुकड़े उपज के लिए इस्तेमाल किया जाना चाहिए। यह एक bazooka के साथ एक मक्खी के लिए लक्ष्य की तरह है ।
मैकिएज एसजे

1
यदि आप ऐप चलाते समय मेमोरी उपयोग की जांच करते हैं, तो आपको जादू दिखाई देगा। यह वास्तव में उस फ़ाइल को खींचता है जिसे आप उस मेमोरी में पढ़ रहे हैं जिसे आप प्रत्येक लाइन के माध्यम से लूप करते हैं, और यह आपके टोकन स्थान को बनाए रखता है। आप वास्तव में स्मृति कुशल होने के लिए फ्लश करना चाहते हैं। php.net/strtok#103051
AbsoluteØER

2
त्वरित ध्यान दें, strtok()उस whileलूप के अंदर किसी और चीज का उपयोग करने से चीजें टूट जाएंगी। मैं भी पहली जगह में एक स्ट्रिंग में सब कुछ हड़पने के लिए इसका इस्तेमाल कर रहा था ( stackoverflow.com/a/2477411/1767412 ) और मुझे एक मिनट का एहसास हुआ कि चीजें नियोजित नहीं थीं
बिलीन्हो

1
सभी विकल्पों में से सबसे तेजी से समाधान, स्वीकृत उत्तर होना चाहिए।
जॉन

94

यदि आपको अलग-अलग प्रणालियों में नए समाचारों को संभालने की आवश्यकता है, तो आप बस PHP पूर्वनिर्धारित निरंतर PHP_EOL (http://php.net/manual/en/reserved.constants.php) का उपयोग कर सकते हैं और नियमित अभिव्यक्ति इंजन के ओवरहेड से बचने के लिए बस विस्फोट का उपयोग करें। ।

$lines = explode(PHP_EOL, $subject);

30
सावधान: यह काम करेंगे विभिन्न प्रणालियों लेकिन यह तार के साथ अच्छी तरह से काम नहीं चलेगा विभिन्न प्रणालियों सेपीएचपी मैनुअल कहा गया है कि PHP_EOL (string)है के लिए प्रतीक सही 'पंक्ति के अंत' इस मंच।
वादीम

@ वादीम सही है! यदि आप एक यूनिक्स सर्वर पर विंडोज टेक्स्ट फाइल को प्रोसेस कर रहे हैं, तो यह विफल हो जाएगा।
जाव्समो

1
सावधान रहें कि आपकी लाइनों की लंबाई के आधार पर, यह बड़ी मात्रा में बड़ी मात्रा में मेमोरी खा सकता है।
सांच्रो

ध्यान दें कि यदि अंतिम पंक्ति में एक लाइन टर्मिनेटर है, तो यह उसके बाद एक और रिक्त स्ट्रिंग भी लौटाएगा।
18:57

20

यह अत्यधिक जटिल और बदसूरत है, लेकिन मेरी राय में यह जाने का तरीका है:

$fp = fopen("php://memory", 'r+');
fputs($fp, $data);
rewind($fp);
while($line = fgets($fp)){
  // deal with $line
}
fclose($fp);

1
+1 और आप php://tempबड़े डेटा को अस्थायी डिस्क फ़ाइल में संग्रहीत करने के लिए भी उपयोग कर सकते हैं ।
CodeAngry

4
यह ध्यान दिया जाना चाहिए कि यह आपको स्ट्रेटोक () समाधान के विपरीत, खाली लाइनों का पता लगाने की अनुमति देता है। प्रलेखन php.net/manual/en/…
जोसिप रोडिन

7
foreach(preg_split('~[\r\n]+~', $text) as $line){
    if(empty($line) or ctype_space($line)) continue; // skip only spaces
    // if(!strlen($line = trim($line))) continue; // or trim by force and skip empty
    // $line is trimmed and nice here so use it
}

^ यह है कि आप लाइनों को कैसे ठीक से तोड़ते हैं , क्रॉस-प्लेटफॉर्म के साथ संगत Regexp:)


6

इसके साथ संभावित स्मृति समस्याएँ strtok:

चूंकि सुझाए गए समाधानों में से एक का उपयोग करता है strtok, दुर्भाग्य से यह एक संभावित मेमोरी इश्यू को इंगित नहीं करता है (हालांकि यह मेमोरी कुशल होने का दावा करता है)। मैनुअल केstrtok अनुसार उपयोग करते समय:

ध्यान दें कि strtok के लिए केवल पहली कॉल स्ट्रिंग तर्क का उपयोग करती है। Strtok को हर बाद की कॉल का उपयोग करने के लिए केवल टोकन की आवश्यकता होती है, क्योंकि यह वर्तमान स्ट्रिंग में कहां है, इसका ट्रैक रखता है।

यह फ़ाइल को मेमोरी में लोड करके करता है। यदि आप बड़ी फ़ाइलों का उपयोग कर रहे हैं, तो आपको उन्हें फ़्लश करने की आवश्यकता है यदि आप फ़ाइल के माध्यम से लूपिंग कर रहे हैं।

<?php
function process($str) {
    $line = strtok($str, PHP_EOL);

    /*do something with the first line here...*/

    while ($line !== FALSE) {
        // get the next line
        $line = strtok(PHP_EOL);

        /*do something with the rest of the lines here...*/

    }
    //the bit that frees up memory
    strtok('', '');
}

यदि आप केवल भौतिक फ़ाइलों से संबंधित हैं (उदाहरण के लिए। डेटामाइनिंग):

मैनुअल के अनुसार , फ़ाइल अपलोड भाग के लिए आप fileकमांड का उपयोग कर सकते हैं :

 //Create the array
 $lines = file( $some_file );

 foreach ( $lines as $line ) {
   //do something here.
 }

4

किरिल का जवाब सबसे अच्छा है, इस पर विचार करते हुए कि आपको अलग-अलग मशीनों पर नई कहानियों को संभालने में सक्षम होना चाहिए।

"मैं ज्यादातर उपयोगी PHP कार्यों की तलाश कर रहा हूं, यह कैसे करना है के लिए एल्गोरिथ्म नहीं। कोई सुझाव?"

मैं इनका भरपूर उपयोग करता हूं:

  • विस्फोट () एक स्ट्रिंग को एक सरणी में विभाजित करने के लिए इस्तेमाल किया जा सकता है, जिसे एक एकल सीमांकक दिया गया है।
  • प्रत्यारोपण () विस्फोट के समकक्ष है, सरणी से वापस स्ट्रिंग पर जाने के लिए।
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.