2016-10-26 1 views
2

У меня есть вход, который имеет несколько полейReplace пространства по-разному в зависимости от снаружи или внутри одиночных кавычек

  • разделенных пробелами,
  • некоторые другие заключены в кавычки, а также разделённых пробелами

Вот пример ввода:

active=1 'oldest active'=0s disabled=0 'function call'=0 

Я бы хотел (а) заменить:

  • всех пространств вне цитаты по | и
  • все внутренние котировки по _

выход будет:

active=1|'oldest_active'=0s|disabled=0|'function_call'=0 

Я пробовал различные решения с sed или perl найти в Интернете но мне этого не удалось, я хочу.

ответ

2
$ s="active=1 'oldest active'=0s disabled=0 'function call'=0" 
$ echo "$s" | perl -pe "s/'[^']*'(*SKIP)(*F)| /|/g; s/ /_/g" 
active=1|'oldest_active'=0s|disabled=0|'function_call'=0 

Двухступенчатая замена:

  • Во-первых, '[^']*'(*SKIP)(*F) будет пропускать все образцы окруженными ' и заменить оставшиеся пробелы с |
  • Во-вторых, пространство в настоящее время остаются внутри ' будут заменены _


Альтернативные решения:

$ echo "$s" | perl -pe "s/'[^']*'/$& =~ s| |_|gr/ge; s/ /|/g" 
active=1|'oldest_active'=0s|disabled=0|'function_call'=0 
  • Вдохновленный из this answer
  • '[^']*'/$& =~ s| |_|gr/ge заменить все пробелы в подходящего шаблона '[^']*', используя другую команду замены. Модификатор e позволяет использовать команду вместо строки в замене секции
  • остальные пространства затем позаботилась с s/ /|/g


Дальнейшее чтение:

+0

Ничего себе, какой быстрый и эффективный ответ! Спасибо за объяснение. Есть ли хорошая документация по всем доступным параметрам (например, SKIP, ...)? – BDR

+0

см. Http://www.rexegg.com/backtracking-control-verbs.html и http://www.rexegg.com/regex-best-trick.html – Sundeep

0

Мы можем использовать регулярное выражение внутри цикла.

$str = "active=1 'oldest active'=0s disabled=0 'function call'=0"; 
print "\nBEF: $str\n"; 
$str =~s#active=1 'oldest active'=0s disabled=0 'function call'=0# my $tmp=$&; $tmp=~s/\'([^\']*)\'/my $tes=$&; $tes=~s{ }{\_}g; ($tes)/ge; $tmp=~s/ /\|/g; ($tmp); #ge; 
print "\nAFT: $str\n"; 

Может быть, некоторые короткие пути будут там кроме этого.

1

Использование Gnu AWK FPAT, вы можете сделать это:

s="active=1 'oldest active'=0s disabled=0 'function call'=0" 

awk -v OFS="|" -v FPAT="'[^']*'[^[:blank:]]*|[^[:blank:]]+" '{ 
    for (i=1; i<=NF; i++) gsub(/[[:blank:]]/, "_", $i)} 1' <<< "$s" 

active=1|'oldest_active'=0s|disabled=0|'function_call'=0 
  • В FPAT регулярное выражение используется чередование для создания полей всех одиночных кавычках значений + стоимость непробельный т.е. '[^']*'[^[:blank:]]* ИЛИ непробельных значений т.е. [^[:blank:]]+ с ввода.
  • Используя gsub, мы просто заменяем все пробелы _, так как мы будем получать пробелы внутри одинарных кавычек во всех полях.
  • Наконец с помощью OFS='|' мы разграничить выход с |

Ссылка:Effective AWK Programming

+1

Хорошо поймать @Sundeep. Теперь это исправлено. – anubhava

1

Это может работать для вас (GNU СЭД):

sed -r ":a;s/^([^']*('[^ ']*')*[^']*'[^' ]*) /\1_/;ta;y/ /|/" file 

Это первый заменяет все пробелы в кавычки строки на _, а затем переводит оставшиеся пробелы в |.

1

@ решение анубхава называет в голове старой школы решения PERL:

$ echo $s | perl -047 -pe "(\$.%2)?s/ /|/g:s/ /_/g;" 
active=1|'oldest_active'=0s|disabled=0|'function_call'=0 

разделить строки на одинарном (047) и к югу на основе чет/нечет.

+0

не нужно использовать двойные кавычки ... 'perl -047 -pe '($.% 2)? S// |/g: s// _/g;'' – Sundeep

+0

true. знак любителя баха. – albe

0
$ awk -F\' '{OFS=FS; for (i=1;i<=NF;i++) gsub(/ /,(i%2?"|":"_"),$i)}1' file 
active=1|'oldest_active'=0s|disabled=0|'function_call'=0