Подставлять текст только между токенами (одной строкой) - PullRequest
0 голосов
/ 13 мая 2018

Я хотел бы удалить пробелы в строках, которые заключены в квадратные скобки, с однострочным вводом.

Точнее, строки, которые соответствуют \[[a-zA-Z0-9 ,]+\] (регистр букв без запятой и пробел между квадратными скобками))

Например:

[ "This is a test": [a, b, c] ]

Должно стать:

[ "This is a test": [a,b,c] ]

Я пробовал несколько попыток с ветвлением, но не смог найти работающий синтаксис.

Например:

/\[[a-zA-Z ,]\+\]/ba; :a;s/ //g;

, но это заменяет пробелы во всей строке, так как sed основывается на строке (мой ввод однострочный).

Я также попробовалКоманда ;e, которая будет работать, если вся строка будет иметь префикс echo " и суффикс ", но тогда это будет escape-ад в одинарных / двойных кавычках (вся строка может содержать ' и ").

GNU sed приветствуется, но я бы хотел, чтобы зависимости были минимальными, поэтому нет perl, если не требуется, и нет ruby, python, php ...

Действительно, я знаю следующееработает отлично, но php слишком большая зависимость:

echo preg_replace_callback(
    "/\[[a-zA-Z ,]+\]/",
    function ($m) { return str_replace(" ", "", $m[0]); },
    '{"a":{"a":{"a":"a b c"},"b":{"b":[a, b]}}}'
);

выходы:

{"a":{"a":{"a":"a b c"},"b":{"b":[a,b]}}}

Ответы [ 2 ]

0 голосов
/ 13 мая 2018

Первый проход - работает, но неуклюже

Вот решение, которое работает с GNU и BSD sed:

sed -E \
    -e '/\[[[:alnum:] ,]+\]/ {
            s/\[([[:alnum:] ,]+)\]/^B\1^E/
            :a
            s/(^B[[:alnum:],]*) +/\1/
            t a
            s/^B/[/
            s/^E/]/
        }' \
    data

Появления ^B и ^E являются управляющими символами ( Control-B и Control-E в оригинале), которые не будут появляться в реальном тексте.(При первом копировании я получил ^B, показывающий как и ^E, показывающий как.)

Объяснение:

  • /\[[[:alnum:] ,]+\]/ { - сопоставление строк, содержащих квадратные скобки, с буквенно-цифровыми символами плюс пробели запятую между ними, и выполните последовательность действий от { до соответствующего }.
  • s/\[([[:alnum:] ,]+)\]/^B\1^E/ - замените квадратные скобки управляющими символами.
  • :a -установите метку
  • s/(^B[[:alnum:],]*) +/\1/ - замените ^B плюс последовательность буквенно-цифровых или запятых (которые захвачены) и строку из одного или нескольких пробелов только с захватом.
  • t a - если команда s/// внесла изменение, вернитесь к метке a.
  • s/^B/[/ - замените ^B на квадратную скобку.
  • s/^E/]/- замените ^E закрывающей квадратной скобкой.
  • } - выполнено

Ответвление необходимо, потому что обычно оператор s/// не сканирует материал, который онтолько что заменил, в то время как крайне важно, чтобы это продолжало повторное сканирование.

С учетом немного более обширного входного файла:

\[[a-zA-Z0-9 ,]+\] (caseless alphanum comma and space, between square brackets)

For example:

[ "This is a test": [a, b c] ]
[ "This is a test": [a, b, c] ]
[ "This is test 3": [  XXX,    YYY,   XXX    ] ]

Should become:

[ "This is a test": [a,bc] ]
[ "This is a test": [a,b,c] ]
[ "This is test 3": [XXX,YYY,XXX] ]

скрипт генерирует:

\[[a-zA-Z0-9 ,]+\] (caseless alphanum comma and space, between square brackets)

For example:

[ "This is a test": [a,bc] ]
[ "This is a test": [a,b,c] ]
[ "This is test 3": [XXX,YYY,XXX] ]

Should become:

[ "This is a test": [a,bc] ]
[ "This is a test": [a,b,c] ]
[ "This is test 3": [XXX,YYY,XXX] ]

Второй проход - платит за просмотр и уточнение

Глядя на него^E не является обязательным, и, возможно, не ^B также.Версия выше имеет дело только с первым таким набором квадратных скобок в строке.Вам нужно более чувствительные регулярные выражения детекторов (те, которые требуют хотя бы одного пробела между маркерами) для обработки нескольких таких шаблонов в одной строке.

Например:

sed -E \
    -e ':a
        /\[[[:alnum:],]* [[:alnum:] ,]*\]/   s/(\[[[:alnum:],]*) +/\1/
        t a' \
    data

Объяснение:

  • :a - установить метку
  • /\[[[:alnum:],]* [[:alnum:] ,]*\]/ - если строка содержит открытую квадратную скобку, ноль или более буквенно-цифровых или запятых символов, один или несколько пробелов,и ноль или более буквенно-цифровых или или запятых или пробелов, за которыми следует закрывающая квадратная скобка, затем…
  • s/(\[[[:alnum:],]*) +/\1/ - заменить открытый квадрат и последовательность из нуля или более буквенно-цифровых или запятых символов и одного илибольше пропусков только по непробелам и…
  • t a - перейти к метке a, если была сделана замена

Дано:

[ "This is a test": [a, b c] ]
[ "This is test 2": [a, b, c] ]
[ "This is test 3": [  XXX   ,    YYY   ,   XXX    ] ]
[ "This is test 4": [  XXX   ,    YYY   ,   XXX    ] [ 1 , 2 , 3 ] ]
[ "This is test 5": [  XXX   ,    YYY   ,   XXX    ] [ 1 , 2 , 3 ] [ abc ] [ ] ]

это дает:

["This is a test": [a,bc] ]
["This is test 2": [a,b,c] ]
["This is test 3": [XXX,YYY,XXX] ]
["This is test 4": [XXX,YYY,XXX] [1,2,3] ]
["This is test 5": [XXX,YYY,XXX] [1,2,3] [abc] [] ]

Это в основном эквивалентно ответу по Beta ;это можно еще больше упростить, исключив совпадение перед командой замены и изменив (слегка усложняя) замену, чтобы она соответствовала работе Beta.

0 голосов
/ 13 мая 2018

Я думаю, что это будет работать:

sed -e ':a' -e 's#\(\[[a-zA-Z0-9,]*\) \([a-zA-Z0-9 ,]*\]\)#\1\2#
t a' filename
...