LinuxForum.Fans
Тема

SED. Поиск строк, содержащих N одинаковых символов

Автор: spronkin1 10 сообщений 4607 просмотров
#356063

Здравствуйте!
Столкнулся со следующей проблемой:
Есть текст, разделенный символами табуляции. Количество символов табуляции в разных строках варьируется.
Как с помощью адресации sed можно отобрать строки, содержащие только 6 символов табуляции? Следует учесть, что символы tab не обязательно идут друг за другом подряд, т.е. между ними может быть текст.

Пробовал использовать такой вариант:

text
sed -e "/\(\t[^\t]*\)\{6\}/!d"

пока не помогает. Скорее всего, я неправильно написал регулярное выражение.
буду дальше думать
PS: просьба не бить сильно руками, использовал GNU sed version 4.0.7 под win32 из unixutils.

#356077

Я бы определял число одинаковых символов в строке с помощью awk,
используя его как этот символ как разделитель. Например, если надо
найти число символов 'f' в переменной $str, то выражение

text
`echo $str | awk -F "f" '{printf("%d",NF)}'`

вернет число, на 1 больше.

Пётр.

#356079
text
#!/usr/bin/perl

while (<>) { chomp; if ( /^([^\t]*\t){6}[^\t]*$/ ) { print "Matched: |$`<$&>$'|\n"; } }

### для проверки
# сохраните этот кусок кода в какой нибудь файл с именем any_file
chmod +x any_file
./any_file text_for_parsing
# где text_for_parsing - это текст в котором хотите найти эти 6 табуляторов

#356182
"spronkin1" написал:
пока не помогает. Скорее всего, я неправильно написал регулярное выражение.

да нет... вроде всё правильно, если «не меньше 6 табов» надо (если надо ровно 6, то сопри регулярку у moshell'а)... разве что в bash пытается интерпретировать восклицательный знак, так что надо писать в одинарных кавычках... или эскейпить...

"spronkin1" написал:
PS: просьба не бить сильно руками,  использовал GNU sed version 4.0.7 под win32 из unixutils.

а как sed запускается? из bash'а? или из cmd? если второе? если второе, то хз как он символы эскейпит... но сдаётся мне, что везде нужен дополнительный бекслеш... а может и два...

#356190
"moshell" написал:
#!/usr/bin/perl

while (<>) {
chomp;
if ( /^([^\t]*\t){6}[^\t]*$/ ) {
print "Matched: |$`<$&>$'|\n";
}
}

Нужен именно однострочник на sed. sed из пакета unixutils запускается из cmd. Можно в linux, главное, чтобы это был однострочник на sed.
PS: и еще: каждая строка начинается с символа tab

#356196
spronkin1 написал:

Нужен именно однострочник на sed

regexp Вам уже дан. включите мозг и перефразируйте его на sed. не всю же жизнь зависеть от кого то

spronkin1 написал:

запускается из cmd.

вот тут различия будут. в какой ОС вы работаете.

spronkin1 написал:

Можно в linux, главное, чтобы это был однострочник на sed.

это к доктору, скоро он придет.

spronkin1 написал:
каждая строка начинается с символа tab

а я дал универсальный ответ. не за что.

#356310
"moshell" написал:
regexp Вам уже дан. включите мозг и перефразируйте его на sed. не всю же жизнь зависеть от кого то

Спасибо за разъяснения. Буду думать, как это реализовать под win32 - нужно, на работе win32, дома linux, поэтому запускаю из wineconsole cmd, конечно, это изврат, но я боюсь, что если я этот скрипт буду реализовывать в native shell, то могу допустить ошибки в win32, например, в виде одинарных кавычек или отсутствия экранирования символов. По-видимому, у меня какой-то глюкодром с cmd.

text
cat serv2.txt | sed -e "s/\t/qqq/g" > temp.txt

заменяет не символ табуляции, а букву t. Даже

text
sed -e "s/\x09/qqq/g" > temp.txt

не хочет заменять tab. Попробую еще сравнить как эти regexp будут работать под win32.

#356342
"moshell" написал:

К сожалению, я пока не изучал Perl, но спасибо за ссылку,

"spronkin1" написал:
cat serv2.txt | sed -e "s/\t/qqq/g" > temp.txt

заменяет не символ табуляции, а букву t. Даже

sed -e "s/\x09/qqq/g" > temp.txt

не хочет заменять tab. Попробую еще сравнить как эти regexp будут работать под win32.

При выполнении указанных команд в cmd.exe под win32 sed отрабатывает успешно. По-видимому, это чистой воды косяк wineconsole cmd. Попробую еще с двойным экранированием \\, но я, конечно расстроен, что wine не поддерживает cmd так как надо в win32.

В win32 соответственно ваш regexp:

text
/^([^\t]*\t){6}[^\t]*$/

будет выглядеть так:

text
"/^\([^\t]*\t\)\{6\}[^\t]*$"

т.е. в sed.exe нужно брать regexp в двойные кавычки "" и, кроме этого, экранировать круглые и фигурные скобки с помощью \ (backslash), хотя значение этих костылей Винды для данного Форума не актуально :)
Мне пригодился ваш скрипт вот в таком случае: в строках, содержащих 8 разделителей, заменить 6 разделитель на 2 разделителя (\tab), с целью выравнивания текста относительно строк, содержащих 9 разделителей:

text
cat.exe "unalign.txt" | sed "/^\([^\t]*\t\)\{8\}[^\t]*$/s/\t/&&/6" > align.txt

Спасибо!

#356567
text
echo -e '1\t2\t3\t4\t5\t6\t7\n1\t2\t3\t4\t5\t6\n\t\t\t\t\t\t1\n' | sed '/\(.*[\t].*\)\{6\}/!d; /\(.*[\t].*\)\{7,\}/d;'
Войдите или зарегистрируйтесь, чтобы ответить.