Регулярное выражение для удаления одинарных кавычек и сохранения апострофов

Я хочу разобрать слова из текстового файла. Апострофы должны быть сохранены, но одинарные кавычки должны быть удалены. Вот некоторые тестовые данные:

john's apostrophe is a 'challenge'

Я экспериментирую с grep следующим образом:

grep -o "[a-z'A-Z]*" file.txt

и он производит:

john's
apostrophe
is
a
'challenge'

Нужно избавиться от этих кавычек вокруг слова challenge.

Правильный/желаемый вывод должен быть:

john's
apostrophe
is
a
challenge

РЕДАКТИРОВАТЬ: Поскольку консенсус, похоже, заключается в том, что апострофы проблематично распознавать, теперь я ищу способ удалить любой апостроф (начальный, конечный, встроенный) из всех слов. Слова должны быть добавлены к словарному указателю. Поиск по фразе также должен удалять апострофы. Для этого может понадобиться еще один вопрос.


person ScrollerBlaster    schedule 21.03.2012    source источник


Ответы (2)


Вот более простой подход только для grep:

grep -E -o "[a-zA-Z]([a-z'A-Z]*[a-zA-Z])?" file.txt

который в Java:

Pattern.compile("[a-zA-Z]([a-z'A-Z]*[a-zA-Z])?")

(Оба из них означают «букву ASCII, за которой может следовать смесь букв ASCII и/или апострофов и буквы ASCII». Идея состоит в том, что совпадающая подстрока должна начинаться с буквы и заканчиваться буквой, но если это длиной более двух символов, то он может содержать апострофы.)

Чтобы принимать буквы, отличные от ASCII, Java можно записать так:

Pattern.compile("\\p{L}([\\p{L}']*\\p{L})?")

Изменить для обновленного вопроса (удалить апострофы): я не думаю, что вы можете сделать это с помощью просто grep; но немного расширив наш репертуар, можно написать:

tr -d "'" file.txt | grep -E -o "[a-zA-Z]+"

или в Java:

String apostrippedStr = str.replace("'", "");

Pattern.compile("[a-zA-Z]+") // or "\\p{L}+" for non-ASCII support
// ... apply pattern to apostrippedStr
person ruakh    schedule 21.03.2012
comment
Э нет. Письмо будет \pL. - person tchrist; 22.03.2012
comment
@tchrist: Perl избаловал тебя; ERE не имеют \p (хотя Java имеет). Но я понимаю вашу точку зрения. ОП использовал A-Z и a-z, поэтому я отредактирую свой ответ, указав букву ASCII. - person ruakh; 22.03.2012
comment
Ага-ага. Я никогда не использую систему grep; У меня есть своя, ты знаешь. Подмножество Java(-7) регулярных выражений Perl — это минимально допустимая система регулярных выражений для современной обработки текста. По крайней мере, он наконец-то соответствует уровню 1 для tr18. - person tchrist; 22.03.2012
comment
Ваш подход может сработать для его небольшой выборки, но настоящие английские слова могут иметь апострофы в конце (подумайте о притяжательных формах множественного числа, таких как названия этих видов) и даже в начале (например, 'tis't not ). Ваш паттерн запрещает падать как на корму, так и на нос, а также не разрешает слова, написанные через дефис. Что ж, если первоначальный кверент об этом не подумал, я полагаю, вам тоже не следует ожидать, что вы приспособитесь к таким вещам. Он просто не будет работать с реальными данными, вот и все. —— Кстати, как и Perl, Java не требует фигурных скобок вокруг свойств, состоящих из одной буквы, поэтому достаточно \pL… и Хаффман торжествует. - person tchrist; 22.03.2012
comment
@tchrist: Вы совершенно правы, но в общем случае программно отличить одинарные кавычки от апострофов невозможно; в крайнем случае, 'n' это буква n в одинарных кавычках или это сокращение для и? (Относительно \pL против \p{L} -- в документации используется последнее, поэтому я считаю его предпочтительным. У Java есть твердая политика быть как можно более подробным. Я не знаю, почему он вообще поддерживает регулярные выражения, но даже там он удалось сделать их длиннее и громоздче.) - person ruakh; 22.03.2012
comment
@tchrist вопрошающий? Я похож на это замечание. С тех пор я думал о конечных и ведущих апострофах. Было бы неплохо их разместить. Возможно, мой вопрос следует отредактировать. Я даю этому как минимум +1, потому что он отлично ответил на мой первоначальный ограниченный вопрос. - person ScrollerBlaster; 22.03.2012
comment
Закрытие этого. Если бы вы могли посмотреть на мое редактирование выше. В качестве быстрой и грязной альтернативы можно ли вместо этого нормализовать слова (удалить все апострофы) перед добавлением их в словарь для поиска в текстовых документах? - person ScrollerBlaster; 22.03.2012
comment
Большое спасибо @ruakh. Кстати, это должно читаться: tr -d "'" <file.txt... - person ScrollerBlaster; 22.03.2012

Вам нужно использовать grep? Вот sed пример на всякий случай:

$ echo "john's apostrophe is a 'challenge'" | sed -re "s/'(\S*)'/\1/g"
john's apostrophe is a challenge

sed — это потоковый редактор, я использовал его для выполнения подстановки (формат s/pattern/subst/, g означает глобальный. Я сопоставляю произвольное количество (*) непробельных символов (\S) и заменяю его той же группой символов, обозначив его как \1 (я записал его круглыми скобками (...).

Редактировать: Хорошо, вот уродливый Perl-подобный пример grep:

$ echo "john's apostrophe is a 'challenge'" | grep -oP "(?<=')\S*(?=')|\w+'?\w*"
john's
apostrophe
is
a
challenge

Я понятия не имею, что я сделал, поэтому вероятно неожиданное поведение :)

С grep я использовал утверждения положительного обзора для соответствия либо слово в одинарных кавычках (утверждения используются для того, чтобы кавычки не были частью совпадения) или (|) слово с необязательным апострофом, которое представлено знаком " один или несколько символов слова" (\w+), за которым следует ' (или нет), а затем, возможно, снова несколько символов слова.

Дополнительные изменения: вот команда sed, которая, кажется, выполняет свою работу и справляется с примером @tchrist:

$ echo "john's apostrophe is a 'challenge'" | sed -re "s/(\W|^) '(\w*)'(\W|$)/\1\2\3/g"
john's apostrophe is a challenge
$ echo "’Tis especially hard, ’tisn’t it now, to leave it for the dogs’ breakfast, let a lone for the cats'" | sed -re "s/(\W|^)'(\w*)'(\W|$)/\1\2\3/g"
’Tis especially hard, ’tisn’t it now, to leave it for the dogs’ breakfast, let a lone for the cats'
person Lev Levitsky    schedule 21.03.2012
comment
Ух ты. Два работающих примера. Теперь, если бы кто-нибудь мог объяснить это. Мне вообще не нужно использовать grep. Изначально проблема возникла из-за желания разобрать слова из текстового файла с помощью Java. Будет ли любой из них работать в Java? - person ScrollerBlaster; 22.03.2012
comment
Разбери меня: ’Tis especially hard, ’tisn’t it now, to leave it for the dogs’ breakfast, let alone for the cats’. ???? - person tchrist; 22.03.2012
comment
Я добавил некоторые пояснения в ответ и, к сожалению, не знаю, как это делается на Java. Как указывает @tchrist, примеры плохо работают с апострофами в начале слов. - person Lev Levitsky; 22.03.2012
comment
Вы можете использовать тот же шаблон с Java, что и там. Он поддерживает все эти вещи. - person tchrist; 22.03.2012
comment
Я обновил ответ, приняв во внимание собачий завтрак, на случай, если вы передумаете :) - person Lev Levitsky; 22.03.2012