sed (выбрать все до N-го вхождения слова)

На самом деле это единственный раздел про unix на этом форуме

Модераторы: /dev/random, Модераторы разделов

Аватара пользователя
sgfault
Сообщения: 586
Статус: -

sed

Сообщение sgfault »

Здравствуйте, снова.

Не уверен, что этого не было, но все же. Меня интересуют варианты решения такой задачи: выбрать N-ое вхождение слова W в строке с помощью sed.
Причем длина слова W может быть любой, но, предположим, что W="abcdef". Т.е задача звучит так: выбрать N-ое вхождение слова 'abcdef' в строке с помощью sed и, например, поставить буквы R и T вокруг выбранного слова.

UPD: мм.. видимо, этот давний вопрос я все же забыл и написал неправильно: N-ое вхождение выбирать неинтересно (это можно сделать и 's//N'), поэтому надо изменить задачу на выбрать все до N-го вхождения включительно (заголовок тоже обновил) :-)
Спасибо сказали:
Аватара пользователя
sgfault
Сообщения: 586
Статус: -

Re: sed

Сообщение sgfault »

sgfault писал(а):
19.02.2010 21:01
Здравствуйте, снова.

Не уверен, что этого не было, но все же. Меня интересуют варианты решения такой задачи: выбрать N-ое вхождение слова W в строке с помощью sed.
Причем длина слова W может быть любой, но, предположим, что W="abcdef". Т.е задача звучит так: выбрать N-ое вхождение слова 'abcdef' в строке с помощью sed и, например, поставить буквы R и T вокруг выбранного слова.

UPD: мм.. видимо, этот давний вопрос я все же забыл и написал неправильно: N-ое вхождение выбирать неинтересно (это можно сделать и 's//N'), поэтому надо изменить задачу на выбрать все до N-го вхождения включительно (заголовок тоже обновил) :-)


Хм.. странно, почему-то мне раньше казалось это сложным. Может я забыл уже тот старый вопрос, но, в таком виде, как я немного запоздало сообразил, вопрос неинтересен - все решается слишком просто :-(

Код: Выделить всё

s/abcdef/&\n/$N
s/\n[^\n]*$//
s/abcdef/REPLACE/


Не надо было тему создавать - маленькая промашка вышла (сотрите что ли?xD).

UPD: Хотя, если вторую часть строки не стирать получается немного сложнее, но все равно просто

Код: Выделить всё

s/abcdef/&\n/$N
h
s/\n[^\n]*$//
s/abcdef/REPLACE/
G
s/\n[^\n]*\n//


обидно даже, что забыл :cray:


UPD 25.02.09:
В двух примерах выше пропущен флаг 'g' в команде s///. Т.е вместо

Код: Выделить всё

s/abcdef/REPLACE/

должно быть

Код: Выделить всё

s/abcdef/REPLACE/g
Спасибо сказали:
Аватара пользователя
sash-kan
Администратор
Сообщения: 13939
Статус: oel ngati kameie
ОС: GNU

Re: sed

Сообщение sash-kan »

sgfault писал(а):
19.02.2010 22:51
[^\n]*$
достаточно и «.*»
Писать безграмотно - значит посягать на время людей, к которым мы адресуемся, а потому совершенно недопустимо в правильно организованном обществе. © Щерба Л. В., 1957
при сбоях форума см.блог
Спасибо сказали:
Аватара пользователя
drBatty
Сообщения: 8735
Статус: GPG ID: 4DFBD1D6 дом горит, козёл не видит...
ОС: Slackware-current

Re: sed

Сообщение drBatty »

sgfault писал(а):
19.02.2010 21:01
UPD: мм.. видимо, этот давний вопрос я все же забыл и написал
неправильно: N-ое вхождение выбирать неинтересно (это можно сделать и 's//N'), поэтому надо изменить задачу на выбрать все до N-го вхождения включительно (заголовок тоже обновил) :-)

я делаю такое с помощью "маркёров" - особых байтов, которых нет в строке. например, используя \n:

Код: Выделить всё

# эта команда заменяет 49е слово на маркёр
s/СЛОВО/\n/49
# а это убирает всё после маркёра, и маркёр тоже
s/\n[^\n]*$//

sgfault писал(а):
19.02.2010 22:51
вопрос неинтересен - все решается слишком просто :-(

не так уж и просто - в вашем коде полно лишнего.
http://emulek.blogspot.ru/ Windows Must Die
Учебник по sed зеркало в github

Скоро придёт
Осень
Спасибо сказали:
Аватара пользователя
drBatty
Сообщения: 8735
Статус: GPG ID: 4DFBD1D6 дом горит, козёл не видит...
ОС: Slackware-current

Re: sed

Сообщение drBatty »

sash-kan писал(а):
20.02.2010 04:18
достаточно и «.*»

угу. если маркёр единственный. но если их много, и нужен последний, то придётся извращаться.
http://emulek.blogspot.ru/ Windows Must Die
Учебник по sed зеркало в github

Скоро придёт
Осень
Спасибо сказали:
Аватара пользователя
RocksLinux
Сообщения: 223
ОС: Slackware

Re: sed

Сообщение RocksLinux »

Я что-то сообразить не могу... А вот если слово не известно, но известен перечень символов из которых оно может состоять, как это нормально (компактно) записать.
Пример:
имеем слова wqes obu amka bbbuo rqwew obobuu wqeq, из них мне надо модифицировать (заменить/удалить) слова, состоящие из символов o b u — как мне это объяснить sed?
Или, что-то более...
Имеем «слова» wqes ob23u 21 amka b3bbuo 11143 rqw2e1w 25 obo1buu wqeq 13421, из них мне надо модифицировать (заменить/удалить) «слова», состоящие только из цифр — как мне это объяснить sed?
«Знать, что мы знаем то, что мы знаем, и что мы не знаем того, чего мы не знаем — это и есть истинное знание». //Конфуций\\
120 минут классики рока
Спасибо сказали:
Аватара пользователя
drBatty
Сообщения: 8735
Статус: GPG ID: 4DFBD1D6 дом горит, козёл не видит...
ОС: Slackware-current

Re: sed

Сообщение drBatty »

RocksLinux писал(а):
20.02.2010 12:10
имеем слова wqes obu amka bbbuo rqwew obobuu wqeq, из них мне надо модифицировать (заменить/удалить) слова, состоящие из символов o b u — как мне это объяснить sed?
Или, что-то более...

только из этих букв?
тогда так:
/\b[obu]+\b/
т.е.:
1)граница слова
2)символы o, b, u любое число раз, не менее одного символа
3)граница слова
Символ \b означает место между буквой и не буквой (\w\W или \W\w), или место между началом строки и буквой, или между буквой и концом строки.
Буквой считается любой символ [a-zA-Z0-9_] и если установлена локаль, то и буквы текущего языка (например у меня - русские. При этом [а-я] работает НЕПРАВИЛЬНО! например в кодировке KOI8-R)
RocksLinux писал(а):
20.02.2010 12:10
Имеем «слова» wqes ob23u 21 amka b3bbuo 11143 rqw2e1w 25 obo1buu wqeq 13421, из них мне надо модифицировать (заменить/удалить) «слова», состоящие только из цифр — как мне это объяснить sed?

это сложнее: придётся явно задавать границы. впрочем с цифрами это не слишком сложно:
/[^0-9]([0-9]+)[^0-9]/
и конечно нужно учесть начало и конец строки.

ЗЫЖ в данном случае границы не нужны - дело в жадности плюса, он и так захватит все цифры от первой нецифры до последней.
http://emulek.blogspot.ru/ Windows Must Die
Учебник по sed зеркало в github

Скоро придёт
Осень
Спасибо сказали:
Аватара пользователя
drBatty
Сообщения: 8735
Статус: GPG ID: 4DFBD1D6 дом горит, козёл не видит...
ОС: Slackware-current

Re: sed

Сообщение drBatty »

drBatty писал(а):
20.02.2010 12:34
/[^0-9]([0-9]+)[^0-9]/

да, многие пишут (что-бы захватить начало и конец строки так:
/(^|[^0-9])([0-9]+)([^0-9]|$)/
и хотя это и работает (вроде-бы), но я так не делаю, как я понял из info, это непереносимая конструкция. Намного проще добавить в начало и конец строки нецифру, например так:

Код: Выделить всё

s/.*/~&~/
# тут обработка
s/^~(.*)~$/\1/
http://emulek.blogspot.ru/ Windows Must Die
Учебник по sed зеркало в github

Скоро придёт
Осень
Спасибо сказали:
Аватара пользователя
t.t
Бывший модератор
Сообщения: 7390
Статус: думающий о вечном
ОС: Debian, LMDE

Re: sed

Сообщение t.t »

drBatty писал(а):
20.02.2010 12:34
RocksLinux писал(а):
20.02.2010 12:10
Имеем «слова» wqes ob23u 21 amka b3bbuo 11143 rqw2e1w 25 obo1buu wqeq 13421, из них мне надо модифицировать (заменить/удалить) «слова», состоящие только из цифр — как мне это объяснить sed?
это сложнее: придётся явно задавать границы. впрочем с цифрами это не слишком сложно:
/[^0-9]([0-9]+)[^0-9]/
и конечно нужно учесть начало и конец строки.
Не понял, чем сложнее? Почему под определение "слова, состоящие только из цифр" не подходит шаблон '\b[0-9]+\b'?

Shell

t:~$ echo qwe 123 qw23er | sed 's/\b[0-9]*\b//g' qwe qw23er
¡иɯʎdʞ ин ʞɐʞ 'ɐнɔɐdʞǝdu qнεиж
Спасибо сказали:
Аватара пользователя
sgfault
Сообщения: 586
Статус: -

Re: sed

Сообщение sgfault »

drBatty писал(а):
20.02.2010 10:46
sgfault писал(а):
19.02.2010 22:51
вопрос неинтересен - все решается слишком просто :-(

не так уж и просто - в вашем коде полно лишнего.

что конкретно? (Кроме '[^\n]*' и '.*')

UPD.

drBatty писал(а):
20.02.2010 12:44
drBatty писал(а):
20.02.2010 12:34
/[^0-9]([0-9]+)[^0-9]/

да, многие пишут (что-бы захватить начало и конец строки так:
/(^|[^0-9])([0-9]+)([^0-9]|$)/
и хотя это и работает (вроде-бы), но я так не делаю, как я понял из info, это непереносимая конструкция. Намного проще добавить в начало и конец строки нецифру, например так:

Код: Выделить всё

s/.*/~&~/
# тут обработка
s/^~(.*)~$/\1/


А ^ и $ в вашем примере разве нужны? Ведь будет работать и без них.
Спасибо сказали:
Аватара пользователя
drBatty
Сообщения: 8735
Статус: GPG ID: 4DFBD1D6 дом горит, козёл не видит...
ОС: Slackware-current

Re: sed

Сообщение drBatty »

t.t писал(а):
23.02.2010 19:17
drBatty писал(а):
20.02.2010 12:34
RocksLinux писал(а):
20.02.2010 12:10
Имеем «слова» wqes ob23u 21 amka b3bbuo 11143 rqw2e1w 25 obo1buu wqeq 13421, из них мне надо модифицировать (заменить/удалить) «слова», состоящие только из цифр — как мне это объяснить sed?
это сложнее: придётся явно задавать границы. впрочем с цифрами это не слишком сложно:
/[^0-9]([0-9]+)[^0-9]/
и конечно нужно учесть начало и конец строки.
Не понял, чем сложнее? Почему под определение "слова, состоящие только из цифр" не подходит шаблон '\b[0-9]+\b'?

Shell

t:~$ echo qwe 123 qw23er | sed 's/\b[0-9]*\b//g' qwe qw23er


Код: Выделить всё

$ echo qwe 123 qw23er | sed 's/.*\b[0-9]*\b//g'"

что-то не так... :)
не, подходит, вот только первая звёздочка всё отъедает напрочь.

А ^ и $ в вашем примере разве нужны? Ведь будет работать и без них.

нет. не нужны. мало того, в моём примере, можно заменить ~ например на `.' (ЛЮБОЙ символ), и всё будет работать, мало того, это всё можно вынести в текст в комментах (который я не показал), но вот только... А что там, в комментах? Для того, что-бы пример был понятен и однозначен, я и написал /^~...~$/, а вовсе не для излишеств.
http://emulek.blogspot.ru/ Windows Must Die
Учебник по sed зеркало в github

Скоро придёт
Осень
Спасибо сказали:
Аватара пользователя
drBatty
Сообщения: 8735
Статус: GPG ID: 4DFBD1D6 дом горит, козёл не видит...
ОС: Slackware-current

Re: sed

Сообщение drBatty »

sgfault писал(а):
24.02.2010 14:11
что конкретно? (Кроме '[^\n]*' и '.*')

sgfault писал(а):
19.02.2010 22:51
s/abcdef/&\n/$N
s/\n[^\n]*$//
s/abcdef/REPLACE/

ну, тогда объясните, почему вы полагаете не лишним СНАЧАЛА заменить "abcdef" на "&\n", а потом удалять всё, что после вставленного только-что \n на "пусто", а потом менять "abcdef" на "REPLACE"? Разве не проще заменить abcdef.* (номер N) на REPLACE и не мучится? Вроде то-же самое...
http://emulek.blogspot.ru/ Windows Must Die
Учебник по sed зеркало в github

Скоро придёт
Осень
Спасибо сказали:
Аватара пользователя
sgfault
Сообщения: 586
Статус: -

Re: sed

Сообщение sgfault »

drBatty писал(а):
24.02.2010 21:32
нет. не нужны. мало того, в моём примере, можно заменить ~ например на `.' (ЛЮБОЙ символ), и всё будет работать

Вы говорите про

Код: Выделить всё

s/.*/~&~/
# тут обработка
s/.(.*)./\1/

?
А что это лучше, чем явно указать '~' ?

drBatty писал(а):
24.02.2010 21:32
мало того, это всё можно вынести в текст в комментах (который я не показал), но вот только... А что там, в комментах? Для того, что-бы пример был понятен и однозначен, я и написал /^~...~$/, а вовсе не для излишеств.

Не понял, что значит вынести в текст в комментах? Объединить с какой-нибудь командой из '# тут обработка' что ли ?

drBatty писал(а):
24.02.2010 21:42
sgfault писал(а):
24.02.2010 14:11
что конкретно? (Кроме '[^\n]*' и '.*')

sgfault писал(а):
19.02.2010 22:51
s/abcdef/&\n/$N
s/\n[^\n]*$//
s/abcdef/REPLACE/

ну, тогда объясните, почему вы полагаете не лишним СНАЧАЛА заменить "abcdef" на "&\n", а потом удалять всё, что после вставленного только-что \n на "пусто", а потом менять "abcdef" на "REPLACE"? Разве не проще заменить abcdef.* (номер N) на REPLACE и не мучится? Вроде то-же самое...


Не понял, как вы вы предлагаете "заменить abcdef.* (номер N) на REPLACE". Так что ли

Код: Выделить всё

s/abcdef.*/REPLACE/N

? Но ведь это не будет работать.
Кроме того, как я только что заметил, в моем втором посте пропущен 'g' (странно, что это до сих пор никто не заметил, ведь мое решение не соответствует названию темы, если без 'g' - "выбрать все до N-го вхождения слова"), т.е должно быть

Код: Выделить всё

s/abcdef/REPLACE/g


PS.
Не говоря уже про то, что вы сами почему-то то же самое написали :unsure:
drBatty писал(а):
20.02.2010 10:46

Код: Выделить всё

# эта команда заменяет 49е слово на маркёр
s/СЛОВО/\n/49
# а это убирает всё после маркёра, и маркёр тоже
s/\n[^\n]*$//
Спасибо сказали:
Аватара пользователя
drBatty
Сообщения: 8735
Статус: GPG ID: 4DFBD1D6 дом горит, козёл не видит...
ОС: Slackware-current

Re: sed

Сообщение drBatty »

sgfault писал(а):
24.02.2010 21:56
А что это лучше, чем явно указать '~' ?

не лучше, а по моему ИМХО - понятнее (для новичков особенно).
sgfault писал(а):
24.02.2010 21:56
Кроме того, как я только что заметил, в моем втором посте пропущен 'g' (странно, что это до сих пор никто не заметил, ведь мое решение не соответствует названию темы, если без 'g' - "выбрать все до N-го вхождения слова"),

Код: Выделить всё

$ echo "ABCDEFG" | sed 's/./!/3g'
AB!!!!!

а вообще - да. тут без вставки \n не получится, вы правы.
http://emulek.blogspot.ru/ Windows Must Die
Учебник по sed зеркало в github

Скоро придёт
Осень
Спасибо сказали:
Аватара пользователя
sgfault
Сообщения: 586
Статус: -

Re: sed

Сообщение sgfault »

drBatty писал(а):
25.02.2010 10:12
sgfault писал(а):
24.02.2010 21:56
А что это лучше, чем явно указать '~' ?

не лучше, а по моему ИМХО - понятнее (для новичков особенно).

аа, тогда понятно :-)

drBatty писал(а):
25.02.2010 10:12

Код: Выделить всё

$ echo "ABCDEFG" | sed 's/./!/3g'
AB!!!!!

Не понял, а ваш пример - это к чему? Ведь ваша конструкция ('Ng') заменяет не все _до_ N-го вхождения, а все _после_ N-го. И использовать ее для удаления всей строки после N-го тоже не получится.. или получится?
Спасибо сказали:
Аватара пользователя
drBatty
Сообщения: 8735
Статус: GPG ID: 4DFBD1D6 дом горит, козёл не видит...
ОС: Slackware-current

Re: sed

Сообщение drBatty »

sgfault писал(а):
25.02.2010 11:35
drBatty писал(а):
25.02.2010 10:12

Код: Выделить всё

$ echo "ABCDEFG" | sed 's/./!/3g'
AB!!!!!

Не понял, а ваш пример - это к чему? Ведь ваша конструкция ('Ng') заменяет не все _до_ N-го вхождения, а все _после_ N-го. И использовать ее для удаления всей строки после N-го тоже не получится.. или получится?

если после Nного стоят только совпадения (как в этом примере) то получится. надо просто менять не на "!", а на "". А вот конструкция вроде
/X.*/N
НЕ работает... Вообще :( Хотя я ещё подумаю над этим...
http://emulek.blogspot.ru/ Windows Must Die
Учебник по sed зеркало в github

Скоро придёт
Осень
Спасибо сказали:
Аватара пользователя
t.t
Бывший модератор
Сообщения: 7390
Статус: думающий о вечном
ОС: Debian, LMDE

Re: sed

Сообщение t.t »

drBatty писал(а):
24.02.2010 21:32
t.t писал(а):
23.02.2010 19:17
drBatty писал(а):
20.02.2010 12:34
RocksLinux писал(а):
20.02.2010 12:10
Имеем «слова» wqes ob23u 21 amka b3bbuo 11143 rqw2e1w 25 obo1buu wqeq 13421, из них мне надо модифицировать (заменить/удалить) «слова», состоящие только из цифр — как мне это объяснить sed?
это сложнее: придётся явно задавать границы. впрочем с цифрами это не слишком сложно:
/[^0-9]([0-9]+)[^0-9]/
и конечно нужно учесть начало и конец строки.
Не понял, чем сложнее? Почему под определение "слова, состоящие только из цифр" не подходит шаблон '\b[0-9]+\b'?

Shell

t:~$ echo qwe 123 qw23er | sed 's/\b[0-9]*\b//g' qwe qw23er

Код: Выделить всё

$ echo qwe 123 qw23er | sed 's/.*\b[0-9]*\b//g'"

что-то не так... :)
не, подходит, вот только первая звёздочка всё отъедает напрочь.
Если нужно (цитирую) "модифицировать (заменить/удалить) «слова», состоящие только из цифр", а не "...от начала до первого «слова» только из цифр", то непонятно, зачем вообще первая звёздочка.
¡иɯʎdʞ ин ʞɐʞ 'ɐнɔɐdʞǝdu qнεиж
Спасибо сказали:
Аватара пользователя
drBatty
Сообщения: 8735
Статус: GPG ID: 4DFBD1D6 дом горит, козёл не видит...
ОС: Slackware-current

Re: sed

Сообщение drBatty »

t.t писал(а):
25.02.2010 15:49
Если нужно (цитирую) "модифицировать (заменить/удалить) «слова», состоящие только из цифр", а не "...от начала до первого «слова» только из цифр", то непонятно, зачем вообще первая звёздочка.

мне уже тоже непонятно:

Код: Выделить всё

$ echo "qwe 123 qw23er" | sed -r 's/([^0-9])([0-9]+)([^0-9])/\1>\2<\3/g'
qwe >123< qw>23<er

хотя это не сработает, если первый и/или посл. символ - цифра.
http://emulek.blogspot.ru/ Windows Must Die
Учебник по sed зеркало в github

Скоро придёт
Осень
Спасибо сказали:
Аватара пользователя
t.t
Бывший модератор
Сообщения: 7390
Статус: думающий о вечном
ОС: Debian, LMDE

Re: sed

Сообщение t.t »

drBatty писал(а):
25.02.2010 16:27
t.t писал(а):
25.02.2010 15:49
Если нужно (цитирую) "модифицировать (заменить/удалить) «слова», состоящие только из цифр", а не "...от начала до первого «слова» только из цифр", то непонятно, зачем вообще первая звёздочка.

мне уже тоже непонятно:

Код: Выделить всё

$ echo "qwe 123 qw23er" | sed -r 's/([^0-9])([0-9]+)([^0-9])/\1>\2<\3/g'
qwe >123< qw>23<er
хотя это не сработает, если первый и/или посл. символ - цифра.
Я никак не пойму, какую задачу Вы решаете, но явно не ту что была поставлена -- "удалить слова, состоящие только из цифр".
¡иɯʎdʞ ин ʞɐʞ 'ɐнɔɐdʞǝdu qнεиж
Спасибо сказали: