2016-05-02 3 views
2

У меня есть список китайских словарных статей (на основе CC-CEDICT), который содержит смесь китайских и латинских символов в следующем формате, разделенных символами новой строки:Python регулярное выражение неожиданно заменяя китайские символы

(источника .txt)

traditional_chars simplified_chars, пиньинь, определение

山牆 山墙, shan1 qiang2, двускатной

В 型 超聲 B 型 超声, В xing2 chao1 sheng1, ти ре-Б ультразвук

Я хотел бы поставить запятую между традиционным и упрощенными символами:

(Желаемый результат)

山牆, 山墙, shan1 qiang2, двускатная

B 型 超聲, B 型 超声, B xing2 chao1 sheng1, тип-B Ультразвук

После некоторых экспериментируя в regex101, я пришел с этим рисунком:

[A-z]*[\u4300-\u9fff]+(\s)[A-z]*[\u4300-\u9fff]+,

Я попытался применить эту модель в Python с помощью следующего кода:

import re 
sourcepath = 'sourcefile.txt' 
destpath = 'result.txt' 
pattern = '[A-z]*[\u4300-\u9fff]+(\s)[A-z]*[\u4300-\u9fff]+,' 

source = open(sourcepath, 'r').read() 
dest = open(destpath, 'w') 
result = re.sub(pattern, ',', source) 
dest.write(result) 
dest.close() 

Но когда я открываю Result.txt, результат Я получаю не то, что я ожидал:

, shan1 qiang2, фронтон

, В xing2 chao1 sheng1, тип-B, ультразвуковая

Я также попытался с помощью модуля регулярных выражений с этой схемой:

[A-z]*\p{Han}(\s)[A-z]*\p{Han}

Но результат был тот же.

Я думал, что, поставив символ \ s в круглые скобки, он сделает группу захвата, и только это пространство будет заменено. Но похоже, что и китайские персонажи тоже заменяются. Я допустил ошибку в регулярном выражении, в коде или обоим? Как мне изменить его, чтобы получить желаемый результат?

+0

Попробуйте 're.sub (г '(I) [AZ] * [\ u4300- \ u9fff] + (= \ s + [AZ] * [\ u4300 - \ u9fff] +) ', r' \ g <0>, ', source) '. Или 're.sub (r '[AZ] * (? = ([\ U4300- \ u9fff] +)) \ 1 (?!,)', R '\ g <0>,', source)' –

+0

Второй также нужен аргумент 'flags = re.I'. Кто-нибудь из них работает? –

+1

, какую версию python вы используете? –

ответ

1

В случае, если у вас есть нечетное число китайских «слов», ваша модель должна учитывать перекрывая матчи. Использование lookaheads:

re.sub(r'(?i)[A-Z]*[\u4300-\u9fff]+(?=\s+[A-Z]*[\u4300-\u9fff]+)', r'\g<0>,', source) 
            ^^^      ^

Или использовать эмуляцию атомной группы с захватом внутри положительного предпросмотра в сочетании с обратной ссылкой в ​​потребляющей шаблоне и опережающий просмотром проверки, если есть запятая уже:

re.sub(r'(?i)[A-Z]*(?=([\u4300-\u9fff]+))\1(?!,)', r'\g<0>,', source) 
        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 

См regex demodemo 2) - обратите внимание на нотацию \x{}, это только для демонстрации, так как я использую опцию PHP).

Смотрите IDEONE Python 3 demo:?

import re 
p = re.compile(r'[A-Z]*(?=([\u4300-\u9fff]+))\1(?!,)', re.IGNORECASE | re.U) 
test_str = "山牆 山墙,shan1 qiang2,gable\nB型超聲 B型超声, B xing2 chao1 sheng1,type-B ultrasound" 
result = p.sub(r"\g<0>,", test_str) 
print(result) 
# => 山牆, 山墙,shan1 qiang2,gable 
# => B型超聲, B型超声, B xing2 chao1 sheng1,type-B ultrasound 
0

Я думал, что, поставив символ \ s в круглые скобки, он сделает группу захвата, и только это пространство будет заменено.

Это не то, как группы захвата работают. Все согласованные все еще заменяются, но с группой захвата вы можете ссылаться на части того, что соответствовало замене.

Я бы изменить две строки вашего скрипта:

pattern = '(?i)([a-z]*[\u4300-\u9fff]+)\s([a-z]*[\u4300-\u9fff]+)' 

И

result = re.sub(pattern, '\g<0>,\g<1>', source) 
+0

Это не будет работать в случае перекрытия строк. –

+0

Правда, если какая-либо из словарных статей содержит три группы китайцев, это не будет помещать запятую между второй и третьей. Тем не менее, я пропустил бит, где плакат сказал, что это возможность в его входном файле. –

0

Испытано на Python 3.5 с примерами кода:

result = re.sub(r"([\u4e00-\u9fff]+)\s+(?:[a-z]+)?([\u4e00-\u9fff]+)", r"\1,\2", subject, 0, re.IGNORECASE) 

Regex Exp lanation

([\u4e00-\u9fff]+)\s+(?:[a-z]+)?([\u4e00-\u9fff]+) 

Options: Case insensitive; Regex syntax only 

Match the regex below and capture its match into backreference number 1 «([\u4e00-\u9fff]+)» 
    Match a single character in the range between these two characters «[\u4e00-\u9fff]+» 
     Between one and unlimited times, as many times as possible, giving back as needed (greedy) «+» 
     The character “一” which occupies Unicode code point U+4E00 «\u4e00» 
     The Unicode character with code point U+9FFF «\u9fff» 
Match a single character that is a “whitespace character” (any Unicode separator, tab, line feed, carriage return, vertical tab, form feed, next line) «\s+» 
    Between one and unlimited times, as many times as possible, giving back as needed (greedy) «+» 
Match the regular expression below «(?:[a-z]+)?» 
    Between zero and one times, as many times as possible, giving back as needed (greedy) «?» 
    Match a single character in the range between “a” and “z” (case insensitive) «[a-z]+» 
     Between one and unlimited times, as many times as possible, giving back as needed (greedy) «+» 
Match the regex below and capture its match into backreference number 2 «([\u4e00-\u9fff]+)» 
    Match a single character in the range between these two characters «[\u4e00-\u9fff]+» 
     Between one and unlimited times, as many times as possible, giving back as needed (greedy) «+» 
     The character “一” which occupies Unicode code point U+4E00 «\u4e00» 
     The Unicode character with code point U+9FFF «\u9fff» 

\1,\2 

Insert the text that was last matched by capturing group number 1 «\1» 
Insert the character string “,” literally «,» 
Insert the text that was last matched by capturing group number 2 «\2» 
+0

копировать и вставлять ошибку из regex ide, tks! –

Смежные вопросы