2009-08-18 10 views
11

Muszę wyczyścić niektóre dane wejściowe z OCR, które rozpoznają pismo ręczne jako bełkot. Wszelkie sugestie dotyczące wyrażeń regularnych do czyszczenia losowych znaków? Przykład:Regex do zastąpienia bełkotu


 
Federal prosecutors on Monday charged a Miami man with the largest 
case of credit and debit card data theft ever in the United States, 
accusing the one-time government informant of swiping 130 million 
accounts on top of 40 million he stole previously. 

, ':, Ie 
':... 11'1 
. '(.. ~!' ': f I I 
. " .' I ~ 
I' ,11 l 
I I I ~ \ :' ,! .~ , .. r, 1 , ~ I . I' , .' I ,. 
, i 
I ; J . I.' ,.\) .. 
. : I 
'I', I 
.' ' 
r," 

Gonzalez is a former informant for the U.S. Secret Service who helped 
the agency hunt hackers, authorities say. The agency later found out that 
he had also been working with criminals and feeding them information 
on ongoing investigations, even warning off at least one individual, 
according to authorities. 

eh....l 
~.\O ::t 
e;~~~ 
s: ~ ~. 0 
qs c::; ~ g 
o t/J (Ii ., 
::3 (1l Il:l 
~ cil~ 0 2: 
t:lHj~(1l 
. ~ ~a 
0~ ~ S' 
N ("b t/J :s 
Ot/JIl:l"-<:! 
v'g::!t:O 
-....c...... 
VI (:ll <' 0 
:= - ~ 
< (1l ::3 
(1l ~ ' 
t/J VJ ~ 
Pl 
..... 
.... 
(II 
+3

+1 bo to ciekawe pytanie, choć podejrzewam, że nie otrzyma odpowiedzi, która działa. –

+0

To jest dobre pytanie, a rozpoznawanie słów/fraz (lub odwrotnie) jest gorącym tematem w ramach sztucznej inteligencji. – Russell

+1

Jestem głęboko przekonany, że REGEX to niewłaściwe narzędzie do tej pracy. – Breton

Odpowiedz

0

Dobrze grupy symboli pasowałby trochę bezsensownego. Być może sprawdzanie w słowniku słów?

Wygląda na to, że istnieje wiele przerw linii, w których występuje bełkot, więc może to być również wskaźnik.

+0

Zrobiłem kilka badań w Uni kilka lat temu wokół ekstrakcji fraz (robisz coś przeciwnego). Istnieje wiele artykułów (np. Http://portal.acm.org/citation.cfm?id=1097059), ale niestety nie ma jednego rozwiązania typu "hit-all". – Russell

0

Interesujący problem.

Jeśli jest to reprezentatywne, prawdopodobnie można zbudować bibliotekę popularnych słów i usunąć linię, która nie pasuje do żadnego z nich.

A może można dopasować znaki i znaki interpunkcyjne i sprawdzić, czy istnieje wiarygodne odcięcie współczynnika lub po prostu częstotliwość występowania niektórych znaków, które oznaczono jako bełkot.

Bez względu na to, myślę, że będzie musiała istnieć jakaś logika programowania, a nie tylko pojedyncze wyrażenie regularne.

0

Przypuszczam, że regex nie pomoże tutaj. Regex w zasadzie pasuje do deterministycznego wejścia, tzn. Regex będzie miał predefiniowany zestaw wzorców, które będzie pasował. W większości przypadków bełkot byłby przypadkowy. Jednym ze sposobów jest odwrócenie problemu, tj. Dopasowanie odpowiedniego tekstu zamiast dopasowania do bełkotu.

1

Jednym z rozwiązań simpleset (nie obejmujące regexpes)

#pseudopython

number_of_punct = suma ([1, jeśli c.ispunct() 0 ° C przez jeszcze ok zgodnie])

if number_of_punct> len (linia)/2: line_is_garbage()

oraz. Lub niegrzeczny wyrażeń regularnych s/[!, "" @ # ~ $%^&] {5,} // g

+0

co z tą linią:, i – Breton

+0

Nic. Usuń go ręcznie później. Nie oczekuj heurystyki, aby usunąć wszystkie śmieci. Przysłowie dnia: "Nie wyrzucaj dziecka z kąpielą". – maykeye

1

Regex nie pomoże tutaj. Powiedziałbym, że jeśli masz kontrolę nad częścią rozpoznawania, a następnie skup się o lepszej jakości: http://www.neurogy.com/ocrpreproc.html

Możesz również poprosić użytkownika o pomoc i określić rodzaj tekstu, z którym pracujesz. Jeśli np. jest to strona z książki, możesz oczekiwać, że większość linii będzie taka sama długość i składa się głównie z liter, spacji i znaków interpunkcyjnych:

0

Zgłaszam żądanie wyrażenia regularnego w rodzaju "jakakolwiek interpunkcja, po której następuje dowolne miejsce oprócz spacji".

więc w .NET jest to prawdopodobnie coś

.Replace("\\p{1,}[a-zA-Z0-9]{1,}", ""); 

Potem rozważyć „dowolne słowo z dwóch lub więcej znaki interpunkcyjne kolejno:

.Replace(" \\p{2,} ", ""); 

wydaje się dobrym początku tak.

+0

> Powiedziałbym, że wyrażenie regularne brzmi "jakakolwiek interpunkcja, po której następuje wszystko oprócz spacji". . Niektóre nazwiska mają łączniki, nie tylko nazwiska (należy pamiętać o niezapominajce). " Cytaty "Zacznij od interpunkcji" – maykeye

+0

Prawda, to nie włączaj podwójnego cudzysłowu w tej części wyrażeń regularnych.Nie sądzę, że on szuka niezawodny system, po prostu coś do zrobienia "pierwszego cięcia" –

+0

Nie zgadzam się. ... :-) –

2

proste heurystyczne, podobny do anonymous odpowiedź:

listA = [0,1,2..9, a,b,c..z, A,B,C,..Z , ...] // alphanumerical symbols 
listB = [[email protected]$%^&...] // other symbols 

Na = number_of_alphanumeric_symbols(line) 
Nb = number_of_other_symbols(line) 

if Na/Nb <= garbage_ratio then 
    // garbage 
+0

Zakłada się, że cała linia jest albo śmieci, albo nie jest, ale na podstawie próbki, jest to uzasadnione, aby założyć. –

+0

tak, służy do filtrowania całych linii. z * normalnym * tekstem nie będzie to takie proste :-) –

2

Nie mam pojęcia, jak dobrze to działa, ale muszę uznać ten problem w przeszłości, bezczynnie. Czasami grałem z małym programowym urządzeniem o nazwie: markov chain Teraz artykuł Wikipedii prawdopodobnie nie będzie miał większego sensu, dopóki nie zobaczysz innych rzeczy, dla których łańcuch Markowa jest dobry. Jednym z przykładów łańcuchów Markowa w akcji jest ten Greeking generator. Innym przykładem jest gregoriański bełkot, który wygląda jak słowa. Łańcuchy Markowa stanowią sposób losowego generowania sekwencji liter, ale ważą losowe wybory w celu naśladowania wzorców częstotliwości badanego korpusu. Na przykład, biorąc pod uwagę literę "T", litera h jest bardziej prawdopodobne, aby pojawić się obok jakiejkolwiek innej litery. Zbadaj więc korpus (powiedzmy, gazety lub posty na blogu), aby wytworzyć rodzaj odcisku palca w języku, na który kierujesz reklamy.

Teraz, gdy masz już tabelę częstotliwości/odcisk palca, możesz sprawdzić przykładowy tekst i ocenić każdą literę zgodnie z prawdopodobieństwem jej pojawienia się. Następnie możesz oznaczyć litery pod określonym progiem prawdopodobieństwa usunięcia. Innymi słowy, zaskakujący filtr. Odfiltruj niespodzianki.

Istnieje pewna swoboda w generowaniu tabel freqency. Nie jesteś ograniczony do jednej litery po drugiej. Możesz zbudować tabelę częstotliwości, która przewiduje, która litera będzie prawdopodobnie podążać za każdym dwuznakiem (grupa dwóch liter), lub każda trigrafia lub quadgraph. Możesz pracować po drugiej stronie, przewidując pojawianie się prawdopodobnych i nieprawdopodobnych trigrafów na pewnych pozycjach, biorąc pod uwagę jakiś poprzedni tekst.

To trochę jak rozmyte wyrażenie. Zamiast MATCHU lub BRAK MECZU, cały tekst jest oceniany na ruchomej skali, zgodnie z tym, jak jest podobny do twojego tekstu referencyjnego.

1

Zrobiłem kombinację eliminującą linie, które nie zawierają co najmniej dwóch 3-literowych słów lub jednego 6-literowego słowa.

([az | AZ] {3} \ s) {2} | ([az | AZ] {6})

http://www.regexpal.com/

+0

Dodałbym porównanie słownikowe, aby upewnić się, że wyrazy, które się znajduje są prawdziwe, a nie tylko losowe. –

0

Lubię odpowiedź @ Bretona - I” d sugeruje użycie swojego podejścia Corpus również z biblioteką znanych "złych skanów", które mogą być łatwiejsze do zidentyfikowania, ponieważ "śmieci" mają bardziej wewnętrzną spójność niż "dobry tekst", jeśli pochodzą ze złych skanów OCR (liczba różnych glifów jest niższe na przykład).

0

Inną dobrą techniką jest użycie sprawdzania pisowni/słownika i wyszukiwanie "słów" po wyeliminowaniu nieczytelnych rzeczy za pomocą wyrażenia regularnego.

1

Oto realizacja Perl z garbage_ratio heurystyki:

#!/usr/bin/perl 

use strict; 
use warnings; 

while (defined(my $chunk = read_chunk(\*DATA))) { 
    next unless length $chunk; 

    my @tokens = split ' ', $chunk; 
    # what is a word? 
    my @words = grep { 
     /^[A-Za-z]{2,}[.,]?$/ 
      or /^[0-9]+$/ 
      or /^a|I$/ 
      or /^(?:[A-Z][.])+$/ 
    } @tokens; 

    # completely arbitrary threshold 
    my $score = @words/@tokens; 
    print $chunk, "\n" if $score > 0.5; 
} 

sub read_chunk { 
    my ($fh) = @_; 
    my ($chunk, $line); 

    while (my $line = <$fh>) { 
     if($line =~ /\S/) { 
      $chunk .= $line; 
      last; 
     } 
    } 

    while (1) { 
     $line = <$fh>; 
     last unless (defined $line) and ($line =~ /\S/); 
     $chunk .= $line; 
    } 

    return $chunk; 
} 


__DATA__ 

Wklej tekst powyżej po __DATA__ powyżej (nie powtarzając tekst tutaj, aby zaoszczędzić miejsce). Oczywiście, użycie sekcji __DATA__ służy do publikowania samodzielnego skryptu. W prawdziwym życiu miałbyś kod, by otworzyć plik itp.

wyjściowa:

 
Federal prosecutors on Monday charged a Miami man with the largest 
case of credit and debit card data theft ever in the United States, 
accusing the one-time government informant of swiping 130 million 
accounts on top of 40 million he stole previously. 

Gonzalez is a former informant for the U.S. Secret Service who helped 
the agency hunt hackers, authorities say. The agency later found out that 
he had also been working with criminals and feeding them information 
on ongoing investigations, even warning off at least one individual, 
according to authorities.
Powiązane problemy