سؤال

خلفية

إنشاء برنامج نصي لحساب تواتر الكلمات في ملف نصي عادي. يقوم البرنامج النصي بالخطوات التالية:

  1. عد تواتر الكلمات من مجموعة.
  2. احتفظ بكل كلمة في الجسوس الموجودة في القاموس.
  3. إنشاء ملف مفصل للفاصلة للترددات.

البرنامج النصي في: http://pastebin.com/vazdekxs

#!/bin/bash

# Create a tally of all the words in the corpus.
#
echo Creating tally of word frequencies...
sed -e 's/ /\n/g' -e 's/[^a-zA-Z\n]//g' corpus.txt | \
  tr [:upper:] [:lower:] | \
  sort | \
  uniq -c | \
  sort -rn > frequency.txt

echo Creating corpus lexicon...
rm -f corpus-lexicon.txt

for i in $(awk '{if( $2 ) print $2}' frequency.txt); do
  grep -m 1 ^$i\$ dictionary.txt >> corpus-lexicon.txt;
done

echo Creating lexicon...
rm -f lexicon.txt

for i in $(cat corpus-lexicon.txt); do
  egrep -m 1 "^[0-9 ]* $i\$" frequency.txt | \
    awk '{print $2, $1}' | \
    tr ' ' ',' >> lexicon.txt;
done

مشكلة

الخطوط التالية تدور باستمرار عبر القاموس لتتناسب مع الكلمات:

for i in $(awk '{if( $2 ) print $2}' frequency.txt); do
  grep -m 1 ^$i\$ dictionary.txt >> corpus-lexicon.txt;
done

إنه يعمل ، لكنه بطيء لأنه يقوم بمسح الكلمات التي عثر عليها لإزالة أي غير موجود في القاموس. يقوم الرمز بتنفيذ هذه المهمة عن طريق مسح القاموس لكل كلمة واحدة. (ال -m 1 المعلمة توقف المسح عند العثور على المطابقة.)

سؤال

كيف يمكنك تحسين البرنامج النصي بحيث لا يتم فحص القاموس من البداية إلى النهاية لكل كلمة واحدة؟ غالبية الكلمات لن تكون في القاموس.

شكرًا لك!

هل كانت مفيدة؟

المحلول

يمكنك استخدام grep -f للبحث عن كل الكلمات في مرور واحد فوق التردد. txt:

awk '{print $2}' frequency.txt | grep -Fxf dictionary.txt > corpus-lexicon.txt
  • -F للبحث عن سلاسل ثابتة.
  • -x لمطابقة الخطوط الكاملة فقط.
  • -f لقراءة أنماط البحث من Dictionary.txt

في الواقع ، يمكنك حتى الجمع بين هذا مع الحلقة الثانية والقضاء على ملف corpus-xicon.txt الوسيط. يمكن استبدال الاثنان للحلقات بواسطة grep واحد:

grep -Fwf dictionary.txt frequency.txt | awk '{print $2 "," $1}'

لاحظ أنني غيرت -x إلى -w.

نصائح أخرى

هذا هو عادة واحد من تلك البرامج النصية التي تكتب في بيرل للسرعة. ولكن إذا ، مثلي ، تكره لغات البرمجة للكتابة فقط ، فيمكنك أن تفعل كل شيء في حالة صفية:

awk '
    BEGIN {
        while ((getline < "dictionary.txt") > 0)
            dict[$1] = 1
    }
    ($2 && $2 in dict) { print $2 }
' < frequency.txt > corpus-lexicon.txt

لا حاجة ل rm -f corpus-lexicon.txt في هذا الإصدار.

استخدم لغة برمجة حقيقية. جميع بدء تشغيل التطبيقات ومسح الملفات تقتلك. على سبيل المثال ، إليك مثال قمت به للتو في بيثون (تقليل خطوط التعليمات البرمجية):

import sys, re
words = re.findall(r'(\w+)',open(sys.argv[1]).read())
counts = {}
for word in words:
  counts[word] = counts.setdefault(word,0) + 1
open(sys.argv[2],'w').write("\n".join([w+','+str(c) for (w,c) in counts.iteritems()]))

اختبارًا مقابل ملف نصي كبير ، كنت جالسًا (1.4 ميجابايت ، 80،000 كلمة وفقًا لـ WC) ، ويكمل هذا في أقل من ثانية (18 كيلو بايت) على PowerMac عمره 5 سنوات.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top