एक स्क्रिप्ट जो पाठ में अक्षरों के बीच अतिरिक्त रिक्त स्थान को हटा देती है


12

मेरे पास एक टेक्स्ट डॉक्यूमेंट है जिसमें टेक्स्ट का भार है जो हर अक्षर के बाद एक अतिरिक्त जगह जोड़ देता है!

उदाहरण:

T h e  b o o k  a l s o  h a s  a n  a n a l y t i c a l  p u r p o s e  w h i c h  i s  m o r e  i m p o r t a n t

दिखने में:

T␣h␣e␣␣b␣o␣o␣k␣␣a␣l␣s␣o␣␣h␣a␣s␣␣a␣n␣␣a␣n␣a␣l␣y␣t␣i ␣c␣a␣l␣␣p␣u␣r␣p␣o␣s␣e␣␣w␣h␣i␣c␣h␣␣i␣s␣␣m␣o␣r␣e␣␣i␣ m␣p␣o␣r␣t␣a␣n␣t ...

ध्यान दें कि हर अक्षर के बाद एक अतिरिक्त जगह होती है, इसलिए लगातार शब्दों के बीच दो स्थान होते हैं।

क्या कोई ऐसा तरीका है जो मुझे मिल सकता है awkया sedअतिरिक्त रिक्त स्थान को हटाने के लिए? (दुर्भाग्य से यह पाठ दस्तावेज़ बड़े पैमाने पर है और मैन्युअल रूप से जाने के लिए बहुत लंबा समय लगेगा।)  मैं सराहना करता हूं कि यह सिर्फ एक सरल बैश स्क्रिप्ट के साथ हल करने के लिए शायद एक बहुत अधिक जटिल समस्या है क्योंकि कुछ प्रकार की पाठ मान्यता भी होनी चाहिए।

मैं इस समस्या से कैसे संपर्क कर सकता हूं?


2
सभी स्थानों को कुछ भी नहीं बदलने के लिए यह तुच्छ है .. लेकिन मुझे लगता है कि आप शब्दों को अलग करना चाहेंगे?
सुंदरदीप

पूर्व के लिए:echo 't h i s i s a n e x a m p l e' | sed 's/ //g'
सुंदरदीप

1
वह अक्षरों के बीच रिक्त स्थान में परिवर्तन को सीमित नहीं करता है । (अंक और विराम चिह्न उदाहरण के लिए अक्षर नहीं हैं )। आप इसे लूप के साथ सिंक में कर सकते हैं। यह भी शायद एक नकल है।
थॉमस डिके

1
केवल पत्रों के बीच में ही सीमित करने के लिए:echo 'T h i s ; i s .a n 9 8 e x a m p l e' | perl -pe 's/[a-z]\K (?=[a-z])//ig'
सुंदरदीप

4
@ जूलीपैलेटियर: मूल संशोधन के स्रोत से पता चलता है कि शब्दों के बीच की जगह दोगुनी हो गई थी। आपने उन्हें अपने संपादन में अन-डबल क्यों किया?
एल'एंडिया स्ट्रैटन

जवाबों:


16

निम्नलिखित regex किसी भी रिक्त स्थान के पहले स्थान को हटा देगा। वह काम करना चाहिए।

s/ ( *)/\1/g

तो कुछ इस तरह:

perl -i -pe 's/ ( *)/\1/g' infile.txt

... एक "निश्चित" संस्करण के साथ infile.txt को प्रतिस्थापित करेगा।


@terdon मैंने हाल के दिनों में देखा है कि लोगों ने पर्ल पाई स्क्रिप्ट लिखना बंद कर दिया है perl -pie- जैसे कि आपके संपादन शो। इसके लिए तर्क क्या है? -पपी ने हमेशा मेरे लिए अच्छा काम किया है, और एक महान महामारी है। क्या हसी का व्यवहार एक विस्तार के रूप में निम्नलिखित कुछ भी व्यवहार करने के लिए बदल गया है, केवल उन चीजों के बजाय जो एक डॉट के साथ शुरू होते हैं? उनके लिए यह बहुत ही मुहावरेदार कुछ तोड़ना अजीब लगेगा।
डेवी मॉर्गन

1
हुह, अच्छी तरह से यह एक मुहावरा नहीं है जिससे मैं परिचित हूँ। जब तक मैं उपयोग कर रहा हूं तब तक पर्ल इस तरह से रहा है -i। दूसरी ओर, मैंने इसे केवल लिनक्स मशीनों पर इस्तेमाल किया है और मुझे इसके बारे में कुछ वर्षों से अधिक जानकारी नहीं है, इसलिए मैं इसके पुराने व्यवहार के बारे में नहीं बोल सकता। हालांकि मेरी मशीन पर, यह:, perl -pie 's/a/b/' fएक त्रुटि पैदा करता है Can't open perl script "s/o/A/": No such file or directory:। जबकि perl -i -pe 's/o/A/' fउम्मीद के मुताबिक काम करता है। तो हाँ, eबैकअप एक्सटेंशन के रूप में लिया जाता है।
terdon

उदास चेहरा। आह, ठीक है, समय आगे बढ़ता है, और इसका मतलब है कि मुझे एक पैरामीटर ऑर्डर को फिर से भरना होगा। मेरे दिमाग को चुस्त-दुरुस्त रखता है, मुझे लगता है। मुझे बताने के लिए धन्यवाद, और मेरे कोड को ठीक करने के लिए!
डेवी मोर्गन

17

का प्रयोग करें wordsegment, एक शुद्ध-अजगर शब्द विभाजन NLP पैकेज:

$ pip install wordsegment
$ python2.7 -m wordsegment <<<"T h e b o o k a l s o h a s a n a n a l y t i c a l p u r p o s e w h i c h i s m o r e i m p o r t a n t"
the book also has an analytical purpose which is more important

1
एनएलपी का उपयोग करना शायद सबसे प्रभावी समाधान है अगर शब्दों को अलग से बताने के लिए और कुछ नहीं है। एनएलपी ज्यादातर मामलों में लुक-फॉरवर्ड शब्दकोश से बेहतर प्रदर्शन करता है।
grochmal

13

इस तथ्य के आधार पर कि इनपुट में शब्दों के बीच दोहरे स्थान शामिल हैं, बहुत सरल समाधान है। आप बस एक अप्रयुक्त चरित्र के लिए डबल स्थान बदलते हैं, रिक्त स्थान को हटाते हैं और अप्रयुक्त वर्ण को एक स्थान पर बदलते हैं:

echo "T h e  b o o k  a l s o  h a s  a n  a n a l y t i c a l  p u r p o s e  w h i c h  i s  m o r e  i m p o r t a n t  " | sed 's/  /\-/g;s/ //g;s/\-/ /g'

... आउटपुट:

पुस्तक में एक विश्लेषणात्मक उद्देश्य भी है जो अधिक महत्वपूर्ण है


5
एक अर्थ के साथ एक सीड कमांड "एक गैर-अंतरिक्ष वर्ण की हर घटना को प्रतिस्थापित करता है, उसके बाद एक स्थान जो कि एक ही गैर-अंतरिक्ष वर्ण के साथ होता है" वही करता है:sed -e "s/\([^ ]\) /\1/g"
वुडेंगॉड

3
यह वास्तव में एक अच्छा विकल्प है। आपको इसका श्रेय पाने के लिए एक उत्तर के रूप में पोस्ट करना चाहिए।
जूली पेलेटियर

10

बचाव के लिए पर्ल!

आपको एक शब्दकोष की आवश्यकता है, यानी प्रति पंक्ति एक शब्द को सूचीबद्ध करने वाली फ़ाइल। मेरे सिस्टम पर, यह मौजूद है /var/lib/dict/words, मैंने भी इसी तरह की फाइलें देखी हैं /usr/share/dict/britishआदि।

सबसे पहले, आपको शब्दकोश से सभी शब्द याद हैं। फिर, आप इनपुट लाइन को लाइन से पढ़ते हैं, और वर्णों को एक शब्द में जोड़ने का प्रयास करते हैं। यदि यह संभव है, तो आप शब्द को याद करते हैं और बाकी पंक्ति का विश्लेषण करने का प्रयास करते हैं। यदि आप लाइन के अंत तक पहुँचते हैं, तो आप लाइन का उत्पादन करते हैं।

#!/usr/bin/perl
use warnings;
use strict;
use feature qw{ say };

my $words = '/var/lib/dict/words';
my %word;

sub analyze {
    my ($chars, $words, $pos) = @_;
    if ($pos == @$chars) {
        $_[3] = 1;  # Found.
        say "@$words";
        return
    }
    for my $to ($pos .. $#$chars) {
        my $try = join q(), @$chars[ $pos .. $to ];
        if (exists $word{$try}) {
            analyze($chars, [ @$words, $try ], $to + 1, $_[3]);
        }
    }
}


open my $WORDS, '<', $words or die $!;
undef @word{ map { chomp; lc $_ } <$WORDS> };

while (<>) {
    my @chars = map lc, /\S/g;
    analyze(\@chars, [], 0, my $found = 0);
    warn "Unknown: $_" unless $found;
}

आपके इनपुट के लिए, यह मेरे सिस्टम पर 4092 संभावित रीडिंग जेनरेट करता है।


से बाहर स्थान दिया गया है संस्करण के साथ परीक्षण में विफल रहता है a cat a logयानीa c a t a l o g
Ctrl-Alt-delor

@richard: OBOE, निश्चित। लेकिन यह अब बहुत अधिक कब्जे उत्पन्न करता है, एक अक्षर शब्द को हटाने की कोशिश करें।
choroba

@richard आप एक गैर-नियतात्मक एल्गोरिथ्म की मदद से इस समस्या से लड़ सकते हैं (जैसे सभी संभव रीडिंग संग्रहीत हैं) और उस पर एक पार्सर लागू करें। तब आप कम से कम त्रुटि गणना के साथ सभी 4000 संभावित रीडिंग को एकल में फ़िल्टर कर सकते हैं।
bash0r

6

नोट: यह उत्तर (यहां कुछ अन्य लोगों की तरह) उस प्रश्न के पुराने संस्करण पर आधारित है जहां शब्दों का सीमांकन नहीं किया गया था। नए संस्करण का तुच्छ उत्तर दिया जा सकता है ।

जैसे इनपुट पर:

T h e b o o k a l s o h a s a n a n a l y t i c a l p u r p o s e w h i c h i s m o r e i m p o r t a n t

तुम कोशिश कर सकते हो:

 $ tr -d ' ' < file | grep -oiFf /usr/share/dict/words | paste -sd ' '
 The book also has ana na l y tic al purpose which ism ore important

यह दाएं से बाएं प्रक्रिया करता है और अगले के बाद एक सबसे लंबा शब्द ढूंढता है।

जाहिर है, यहाँ, यह शब्दों का सबसे अच्छा चयन नहीं है क्योंकि इस वाक्य का कोई मतलब नहीं है, लेकिन सही के साथ आने के लिए, आपको पाठ के व्याकरण या अर्थ या कम से कम कुछ सांख्यिकीय को समझने में सक्षम टूल की आवश्यकता होगी शब्दों के सबसे संभावित सेट के साथ आने के लिए कौन से शब्द एक साथ पाए जाने की संभावना है। लगता है कि समाधान एक विशेष पुस्तकालय है जैसा कि लिन ने पाया है


@terdon, संपादित देखें। समस्या यह है कि प्रश्न को जटिल और दिलचस्प से एक तुच्छ में बदल दिया गया था। क्या कोई ऐसा तरीका है जिससे आप इसे दो प्रश्नों में विभाजित कर सकते हैं जो यह संपादन से पहले और बाद में था?
स्टीफन चेजालस

मुझे डर है, नहीं। अभी भी एक चालाक चाल हालांकि, भले ही सही नहीं है।
terdon

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

2

डेवी मॉर्गन के संस्करण के समान, लेकिन sed के साथ:

$ echo "f o o  t h e  b a r" | sed -r "s/[ ]{1}([^ ]{1})/\1/g"
foo the bar

यह sedकेवल GNU है और यह डेवी के बराबर नहीं है। sedडेवी के मानक के बराबर होगाsed 's/ \( *\)/\1/g'
स्टीफन चेज़लस

ध्यान दें "समान" ;-)
जलेक्स

1

हालांकि यह एक पर्ल-लाइनर के साथ किया जा सकता है (और होना चाहिए), एक छोटा सी पार्सर बहुत तेज़ होगा, और यह बहुत छोटा भी है (और उम्मीद है कि बहुत सही है):

#include <stdio.h>
#include <stdlib.h>

int main()
{
  char c1 = '\0', c2 = '\0', tmp_c;

  c1 = fgetc(stdin);
  for (;;) {
    if (c1 == EOF) {
      break;
    }
    c2 = fgetc(stdin);
    if (c2 == EOF) {
      if (c1 != ' ') {
        fputc(c1, stdout);
      }
      break;
    }
    if (c1 == c2 && c1 == ' ') {
      tmp_c = fgetc(stdin);
      if (tmp_c != EOF) {
        if (tmp_c != '\n') {
          ungetc(tmp_c, stdin);
          fputc(' ', stdout);
        } else {
          ungetc(tmp_c, stdin);
        }
      } else {
        break;
      }
    } else if (c1 != ' ') {
      fputc(c1, stdout);
    }
    c1 = c2;
  }
  exit(EXIT_SUCCESS);
}

के साथ संकलित किया

gcc-4.9 -O3 -g3  -W -Wall -Wextra -std=c11 lilcparser.c -o lilcparser

(प्रोग्राम 9kb से थोड़ा कम है)

जैसे पाइप में उपयोग करें:

echo "T h e  b o o k  a l s o  h a s  a n  a n a l y t i c a l  p u r p o s e  w h i c h  i s  m o r e  i m p o r t a n t  " | ./lilcparser

1

मैंने यह कोशिश की और यह काम करने लगता है:

echo "<text here>" | sed -r 's/(\w)(\s)/\1/g'

sedआदेश दो समूहों और रिटर्न केवल पहले कैप्चर करता है।


0

सी ++ में, मैं यह करूंगा:

#include <fstream>
using namespace std;

int main()
{   
    fstream is("test.txt", std::ios::in);

    char buff;
    vector<char>str;

    while (!is.eof()){is.get(buff);str.push_back(buff);} //read file to string

    for (int a=0;a<str.size();++a)if (str[a] == ' ' && str[a + 1] != ' ')str.erase(str.begin()+a);
    is.close();

    ofstream os("test.txt", std::ios::out | std::ios::trunc); //clear file for rewrite

    os.write(str.data(), str.size() * sizeof(char)); //write chars
    os.close();

    return 0;
    }

परीक्षण पाठ फ़ाइल की सामग्री को एक ही स्ट्रिंग में बदल देगा, लेकिन हटाए गए अक्षरों के बीच रिक्त स्थान के साथ। (इसे सटीक होने के लिए हर अक्षर के बीच जगह की आवश्यकता होती है)।


0
$ echo 'F o u r  s c o r e  a n d' | \
txr -t '(mapcar* (opip (split-str @1 "  ")
                       (mapcar (op regsub #/ / ""))
                       (cat-str @1 " "))
                 (get-lines))'
Four score and


$ txr -e '(awk (:begin (set fs "  "))
               ((mf (regsub #/ / ""))))'  # mf: modify fields
F o u r  s c o r e  a n d
Four score and


$ awk -F'  ' '{for(i=1;i<=NF;i++)gsub(/ /,"",$i);print}'
F o u r  s c o r e  a n d
Four score and
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.