Сделайте sed заменить ТОЛЬКО точные строки - PullRequest
0 голосов
/ 26 июля 2011

У меня есть файл css, подобный следующему:

    #layout.one-column  #menu-secondary{background: #3c3c3c; height: 20px; font-family: 'Trebuchet MS'; font-weight: bold; font-size: 15px; padding: 10px;}     
    #layout.one-column  #menu-secondary a {color: #FFF; text-decoration: none;}
    #layout.one-column  #menu-secondary ul {}   
    #layout.one-column  #menu-secondary ul li {display: block; height: 30px; float: left; margin: 0 20px 0 0;}  
    .ofr h2 {font-size: 17px; height: 35px; margin: 0 10px 10px 10px;}  
    .ofr h2 a {color: #2a2a2a; text-decoration: none;}      
    #layout.one-column  #menu-secondary ul li.active {background: url(../img/selected.gif) no-repeat bottom center;}
    #layout.one-column  #menu-secondary ul li a {display: block; float: left; padding: 0 10px;}     
    #layout.one-column  #menu-secondary ul li a:hover {text-decoration: underline;}  

Как вы можете видеть, каждая строка в начале имеет табуляцию / пару пробелов, и строка начинается с .whwhat / # чем угодно.Я кодировал небольшой сценарий, который в какой-то момент запускается:

find css/myCSS.css -name "*.css" -type f -exec sed -i "s/\<$pattern\>/$replacer/g" {} \;

, где $pattern может быть #layout, а $replacer может быть #LAYOUT.То, что я хотел бы сделать, и, очевидно, я делаю это неправильно, это заменить #layout на #LAYOUT, если строки

  • равны (blank spaces/tabs before and after the $pattern)
  • равно (blank spaces/tabs just before the $pattern), затем dot плюс все (#pattern.whatever)
  • равно (blank spaces/tabs just before the $pattern), затем # плюс все (#pattern#whatever)
  • как #whatever.pattern или # любой # шаблон (blank spaces/tabs just before the #whatever and after #pattern).

Надеюсь, я сделал это сейчас, cristal clear :)

Вот несколько примеров, в каждой строке нужно заменить #pattern или .pattern:

#pattern     <- blank spaces/tabs before and after the string  
#pattern.bar <- blank spaces/tabs before #pattern  and after .bar  
.pattern#bar <- blank spaces/tabs before .pattern  and after #bar  
#foo.pattern <- blank spaces/tabs before #foo and after .pattern  
.foo#pattern <- blank spaces/tabs before .foo and after #pattern  
.pattern     <- blank spaces/tabs before and after the string   

Я пытался сделать это с помощью sed, но не могу дозвониться и подумал, что могу быть «легким» для того, кто ежедневно работает с sed.Еще раз спасибо :)

Ответы [ 3 ]

2 голосов
/ 26 июля 2011

Если вы хотите переопределить границы слов для своих нужд, вам нужно перечислить их. Один из подходов состоит в том, чтобы взять шаблон границы и добавить его в конце:

echo "well #menu not #menu-foo #menu" | sed -r 's/#menu([ \t\n\r.!?,]|$)/#MENU\1/g'
well #MENU not #menu-foo #MENU

|$ - захватить конец файла / конец регистра ввода.

Я до сих пор не знаю роли ведущего #, но, думаю, вы можете применить эту идею до сих пор, если вам нужно что-то вроде \ 1MENU \ 2 для первого шаблона разделителя.

обновление 28.07, 23: 45:

  • равно (пусто / табуляция до и после шаблона $) [ \t]pattern[ \t]
  • равно (пробел / табуляция перед шаблоном $), затем точка плюс все что угодно (# pattern.whwhat) [ \t]pattern.[^ \t] исчерпывающее описание «что угодно» было бы лучше. Допустимы дополнительные точки - как мы можем распознать, что «все» закончилось? Пробелы
  • равно (пусто / табуляция непосредственно перед шаблоном $), затем # плюс все что угодно (# образец # все что угодно) [ \t]pattern#[^ \t] хорошо, это то же самое, что и выше, просто хэш вместо точки.
  • как у шаблона # what.pattern или # what # (пробел / табуляция перед #whither и после #pattern). [ \t]#[^ \t].pattern[ \t] или [ \t]#[^ \t]#pattern[ \t]

Нет. 2 и 3 почти одинаковы. Если мы имеем в виду A или B, мы можем просто сформировать группу [#.]. Внутри группы нам не нужно маскировать точку, потому что точка как джокер не имеет никакого смысла в группе.

Нет. Таким образом, 2 и 3 вместе взятых

[ \t]pattern[#.][^ \t][ \t]

Но! Вы ничего не делаете с «чем угодно». Что бы это ни было, оно не изменилось. Итак, мы добавляем # и. просто к списку разделителей (пробел и табуляция) и вернуть их (или пробел или табуляцию), какими бы они ни были:

[ \t]pattern([#. \t])

Простой тест:

echo "well #menu not #menu-false #menu.dot #menu#hash" \
| sed -r 's/[ \t]#menu([#. \t])/ #MENU\1/g' 
well #MENU not #menu-false #MENU.dot #MENU#hash

Это изменило бы объект перед #Menu, будь то пустым или табуляцией, всегда пустым. Мы могли бы захватить это тоже, если хотели.

| sed -r 's/([ \t])#menu([#. \t])/\1#MENU\2/g' 

Но как насчет последнего правила, номера 4, где «что угодно» ведет «образец»? Мы можем объединить точку и хэш:

[ \t]#[^ \t][.#]menu[ \t]

Объединение этого случая в нашем регулярном выражении позволило бы # foo # pattern # bar. Это становится сложным. Нам лучше начать новую, новую команду:

s/([ \t]#[^ \t]+[.#])menu[ \t]/\1MENU /g'

, к которому можно добавить ';' после предыдущего:

| sed -r 's/[ \t]#menu([#. \t])/ #MENU\1/g;s/([ \t]#[^ \t]+[.#])menu[ \t]/\1MENU /g'

Так что, я думаю, я решил ваши 4 правила, но пример вверху касается только двух из них. И ваша попытка снова включает \< и \>, что только сбивает с толку.

Вот мой самодельный пример, включая случай для правила 4:

echo "well #bar.menu and #foo#menu #menu not #menu-false #menu.dot #menu#hash" \
| sed -r 's/[ \t]#menu([#. \t])/ #MENU\1/g;s/([ \t]#[^ \t]+[#.])menu[ \t]/\1MENU /g'

well #bar.MENU and #foo#MENU #MENU not #menu-false #MENU.dot #MENU#hash
1 голос
/ 26 июля 2011

Переписано на основе вопроса переписать.Внимание, здесь играют в некоторые игры с цитатами:

pattern="layout"
replace="FOO"

sed 's/\([ \t#.]\)'"$pattern"'\([ \t#.]\)/\1'"$replace"'\2/g'  << EXAMPLE

 #layout  #layout.whatever #layout#whatever
 #whatever.layout #whatever#layout
 .layout .layout.whatever .layout#whatever
EXAMPLE

производит

 #FOO  #FOO.whatever #FOO#whatever
 #whatever.FOO #whatever#layout
 .FOO .FOO.whatever .FOO#whatever
1 голос
/ 26 июля 2011

ОБНОВЛЕНИЕ 2

ОК, вам нужно сопоставить целые слова, которые начинаются с # или . и являются допустимым идентификатором CSS, а затем могут заканчиватьсяCSS цепочка или пробелы.И они также могут быть в конце цепочки CSS?

sed -i "s/\(\s+|[#.][a-z_][a-z0-9_-]*\)#pattern\(\s+|[#.:]\)/\1#PATTERN\2/"

Это ужасно и все прописано.Я проверил спецификацию CSS, чтобы убедиться, что у меня есть правильный шаблон для идентификаторов селектора.В группе терминалов : из-за псевдоселекторов.

OLDER STUFF

\b не будет работать для вас (потому что вы считаете # menu-foo отдельным элементом и \ b видит его как четыре вещи# menu - foo.)

Прежде чем мы сможем вам помочь, вам нужно уточнить, что вы считаете «разрывом слов».Как минимум, вы можете попробовать свой sed следующим образом, если разрывы в пробелах - это то, что вы считаете достаточно:

sed -i "s/\(\s\)#menu\(\s\)/\1#MENU\2/"

С другой стороны, вам придется указать, из чего состоит разрыв слова.Вместо \ s вам может понадобиться \(^|[\s"']\) для начала и что-то очень уродливое для конечного условия.

На основании вашего комментария, если каждый ваш токен находится между HTML-тегами, вы можете сделать что-то вродеследующий.Уберите -i из строки sed, если вы не хотите учитывать регистр символов.На данный момент мой единственный вопрос будет, если в ваших данных также есть разрывы строк.Разве весь HTML-код находится в одной текстовой строке?

sed -i "s/>#menu</>#MENU</"

или, что интереснее, включая возможные разрывы строк:

sed -i "s/\(^|>\)#menu\($|<\)/\1#MENU\2/"

Нам могут потребоваться образцы данных, чтобы выйти за рамки этого ...

...