2014-06-20 14 views
7

Piszę serię testów dla solwera. Natknąłem się na ciekawą palindrom po hebrajsku:Jak wykryć palindrom w języku hebrajskim?

טעם לפת תפל מעט

Który jest palindrom, ale litera Mem ma zarówno regularną formę (מ) i "ostateczny kształt" (ם), jak wygląda jako ostatnia litera w słowie. Ale w przeciwieństwie do twardego kodu, który "0x5de => 0x5dd" w moim programie, nie byłem w stanie znaleźć sposobu, aby programowo polegać na Unicode, Pythonie lub bibliotece, która traktowałaby te dwa jako takie same. Rzeczy, które wypróbowałem:

s = 'טעם לפת תפל מעט' 
s.casefold() # Python 3.4 
s.lower() 
s.upper() 
import unicodedata 
unicodedata.normalize(...) # In case this functioned like a German Eszett 

Wszystkie przyniosły ten sam ciąg. Inne hebrajskie litery, które spowodowałyby ten problem (na wypadek gdyby ktoś wyszukał to później) byłyby Kaf, Nun, Peh i Tsadeh. Nie, nie jestem native speakerem języka hebrajskiego.

+0

Czy to jedyne 5 liter, które mogłyby mieć ten problem? – Dannnno

+0

Dlaczego to robisz? Jestem po prostu ciekawy –

+0

Jestem instruktorem programowania, próbuję wykonać ćwiczenie, które ma proste rozwiązanie (czy słowo palindrom?), Rozwiązanie pośrednie (czy to angielskie wyrażenie jest palindromem?) I trudne rozwiązanie (czy ten arbitralny zestaw "liter" jest palindromem?). – heptadecagram

Odpowiedz

1

Oto brzydki rozwiązanie, które działa na bieżącym numerze:

import unicodedata 

def make_map(ss): 
    return [unicodedata.name(s).split(' ')[-1] for s in ss] 

def is_palindrome(ss): 
    return make_map(ss) == make_map(reversed(ss)) 

ta polega na formatowaniu hebrajskich imion postaci w tabeli przeglądowej Pythona, choć, więc może nie uogólniać doskonale.

Konkretnie, masz:

In [29]: unicodedata.name(s[2]) 
Out[29]: 'HEBREW LETTER FINAL MEM' 
... 
In [31]: unicodedata.name(s[-3]) 
Out[31]: 'HEBREW LETTER MEM' 

Więc stripping się wszystkich, ale ostatnie słowo daje:

In [35]: [unicodedata.name(s_).split(" ")[-1] for s_ in s] 
Out[35]: ['TET', 'AYIN', 'MEM', 'SPACE', 'LAMED', 'PE', 'TAV', 'SPACE', 'TAV', 'PE', 'LAMED', 'SPACE', 'MEM', 'AYIN', 'TET'] 

o to samo w odwrotnej kolejności. Unicode to jednak wielki świat, więc nie jestem pewien, czy nie można zbudować przykładu, który go pokona.

+0

To interesujące podejście, ale nie powiedzie się na literach z akcentami, uznając je wszystkie za równe: "LATIN CAPITAL LETTER A WITH GRAVE", "LATIN CAPITAL LETTER E WITH GRAVE". – heptadecagram

+0

W tym przypadku możesz zignorować "FINAL", co stanowi jedyną różnicę w nazwie postaci ... –

+0

@heptadecagram Myślę, że zawsze możesz znaleźć dziwnie nazwaną postać Unicode, która przełamuje określone podejście. Istnieje [wiele znaków Unicode] (http://www.unicode.org/Public/6.3.0/ucd/NamesList.txt) i jeśli musisz zająć się wszystkim, od "CEDILLA" do "PRAWEJ POINTINGA PODWÓJNIE KĄTEM" ZNAK CYTATYCZNY "do" FRAKCJI TRUDNOŚCI VULGAR "do" LATIN MAŁA LISTA O Z OGONEK I MACRON "do" OSOBA BIURO INFORMACJI "do .... itd. Myślę, że jesteś SOL. –

2

Możesz podać nieco bardziej "rygorystyczną" odpowiedź (taką, która jest mniej prawdopodobne, aby dać fałszywe pozytywne i fałszywe negatywy), z nieco więcej pracy. Zauważ, że odpowiedź Patricka Collina może się nie udać, dopasowując wiele niepowiązanych ze sobą znaków, ponieważ dzielą one ostatnie słowo w ich nazwie danych Unicode.

Jedną rzeczą, jaką można zrobić, jest bardziej rygorystyczne podejście do przemiany końcowych liter:

import unicodedata 

# Note the added accents 
phrase = 'טעם̀ לפת תפל מ̀עט' 

def convert_final_characters(phrase): 
    for character in phrase: 
     try: 
      name = unicodedata.name(character) 
     except ValueError: 
      yield character 
      continue 

     if "HEBREW" in name and " FINAL" in name: 
      try: 
       yield unicodedata.lookup(name.replace(" FINAL", "")) 
      except KeyError: 
       # Fails for HEBREW LETTER WIDE FINAL MEM "ﬦ", 
       # which has no non-final counterpart 
       # 
       # No failure if you first normalize to 
       # HEBREW LETTER FINAL MEM "ם" 
       yield character 
     else: 
      yield character 

phrase = "".join(convert_final_characters(phrase)) 
phrase 
#>>> 'טעמ̀ לפת תפל מ̀עט' 

To właśnie szuka znaków hebrajskich gdzie „FINAL” może być usunięta, a robi.


Można również konwertować do grafemów za pomocą the "new" regex module on PyPI.

import regex 

# "\X" matches graphemes 
graphemes = regex.findall("\X", phrase) 
graphemes 
#>>> ['ט', 'ע', 'מ̀', ' ', 'ל', 'פ', 'ת', ' ', 'ת', 'פ', 'ל', ' ', 'מ̀', 'ע', 'ט'] 

graphemes == graphemes[::-1] 
#>>> True 

ta zajmuje się akcentów i innych znaków łączących.