(grep) Regex, aby dopasować znaki spoza ASCII?

169

W systemie Linux mam katalog z dużą ilością plików. Niektóre z nich mają znaki spoza ASCII, ale wszystkie są poprawnymi kodami UTF-8 . Jeden program ma błąd, który uniemożliwia mu pracę z nazwami plików spoza ASCII i muszę dowiedzieć się, na ilu z nich ma to wpływ. Zamierzałem to zrobić, finda następnie wykonać polecenie grep, aby wydrukować znaki spoza ASCII, a następnie zrobić, wc -laby znaleźć liczbę. Nie musi to być grep; Mogę użyć dowolnego standardowego wyrażenia regularnego Unix , takiego jak Perl , sed , AWK itp.

Czy jednak istnieje wyrażenie regularne dla „dowolnego znaku, który nie jest znakiem ASCII”?

Rory
źródło
1
Paul, tak, mogę używać perla
Rory
/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F-\x9F]
Tinmarino,

Odpowiedzi:

310

Dopasuje to pojedynczy znak spoza zestawu ASCII:

[^\x00-\x7F]

To jest poprawne PCRE ( wyrażenie regularne zgodne z Perlem ).

Możesz także użyć skrótów POSIX :

  • [[:ascii:]] - dopasowuje pojedynczy znak ASCII
  • [^[:ascii:]] - dopasowuje pojedynczy znak inny niż ASCII

[^[:print:]] prawdopodobnie wystarczy. **

Alix Axel
źródło
3
@adrianm: Nie, ^obowiązuje w PCRE.
Alix Axel
10
Dokładnie tak. Jednak musisz użyć programu pcregrep, a nie standardowego grep. [^ [: print:]] nie będzie działać, jeśli twój terminal jest skonfigurowany w UTF8.
Rory
@Rory, dlaczego :print:nie działa w terminalu UTF8? To działa dla mnie w 27.chr =~ /[^[:print:]]/
podważonym
Jest to naprawdę przydatne do naprawiania złych nazw plików - rename 's/[^\x00-\x7F]//g' *(możesz najpierw -nsprawdzić, czy zmiany są prawidłowe).
naught101
Jak dopasować dowolny znak inny niż UTF8 i inne określone znaki?
CMCDragonkai
37

Nie, [^\x20-\x7E]to nie jest ASCII.

To jest prawdziwy ASCII:

 [^\x00-\x7F]

W przeciwnym razie usunie nowe linie i inne znaki specjalne, które są częścią tabeli ASCII!

Peter L.
źródło
3

[^\x00-\x7F]i [^[:ascii:]]pomijają niektóre bajty sterujące, więc ciągi znaków mogą być czasami lepszą opcją. Na przykład cat test.torrent | perl -pe 's/[^[:ascii:]]+/\n/g'zrobi dziwne rzeczy na twoim terminalu, gdzie strings test.torrentzachowa się jak.

user1133275
źródło
3

Aby sprawdzić poprawność pola tekstowego Zaakceptuj tylko Ascii, użyj tego wzorca

[\x00-\x7F]+

Othman Mahmoud
źródło
3

Używam [^\t\r\n\x20-\x7E]+i wydaje się, że działa dobrze.

SolidSnakeUk89
źródło
2

Możesz użyć tego wyrażenia regularnego:

[^\w \xC0-\xFF]

Case ask, opcje to Multiline .

CypherPotato
źródło
2

Naprawdę nie potrzebujesz wyrażenia regularnego.

printf "%s\n" *[!\ -~]*

Spowoduje to również wyświetlenie nazw plików ze znakami sterującymi w nazwach, ale uważam to za funkcję.

Jeśli nie masz żadnych pasujących plików, glob rozwinie się do samego siebie, chyba że nullglobustawiłeś. (Wyrażenie nie pasuje do siebie, więc z technicznego punktu widzenia dane wyjściowe są jednoznaczne).

tripleee
źródło
Opóźnieniem, mogę stwierdzić, że to robi pracę prawidłowo, jeśli rzeczywiście mają jakieś pliki, które pasują do tego wzorca. Zachowanie, w którym wzór drukuje się, gdy nie ma dopasowań, jest nieco zaskakujące, ale w rzeczywistości poprawne. Zredagowałem odpowiedź, aby to wyjaśnić.
tripleee
1

Okazało się, że jest to bardzo elastyczne i rozszerzalne. $ field = ~ s / [^ \ x00- \ x7F] // g; # w ten sposób można wyczyścić wszystkie elementy spoza ASCII lub określone elementy. Bardzo przyjemny w wyborze lub wstępnym przetwarzaniu elementów, które ostatecznie staną się kluczami mieszania.

Don Turnblade
źródło