Регулярное выражение – заменить все пробелы в начале строки на периоды

Меня не волнует, если я достиг этого через vim, sed, awk, python и т. Д. Я пробовал все, не мог сделать это.

Для ввода:

top f1 f2 f3 sub1 f1 f2 f3 sub2 f1 f2 f3 sub21 f1 f2 f3 sub3 f1 f2 f3 

Я хочу:

 top f1 f2 f3 ...sub1 f1 f2 f3 ...sub2 f1 f2 f3 ......sub21 f1 f2 f3 ...sub3 f1 f2 f3 

Затем я хочу просто загрузить это в Excel (ограниченное пробелом) и по-прежнему смотреть на иерархию первого столбца!

Я много пробовал, но в итоге теряю информацию о иерархии

5 Solutions collect form web for “Регулярное выражение – заменить все пробелы в начале строки на периоды”

С этим в качестве входа:

 $ cat file top f1 f2 f3 sub1 f1 f2 f3 sub2 f1 f2 f3 sub21 f1 f2 f3 sub3 f1 f2 f3 

Пытаться:

 $ sed -E ':a; s/^( *) ([^ ])/\1.\2/; ta' file top f1 f2 f3 ...sub1 f1 f2 f3 ...sub2 f1 f2 f3 ......sub21 f1 f2 f3 ...sub3 f1 f2 f3 

Как это работает:

  • :a

    Это создает метку a .

  • s/^( *) ([^ ])/\1.\2/

    Если строка начинается с пробелов, это заменяет последнее пространство в ведущих пространствах периодом.

    Более подробно, ^( *) соответствует всем ведущим записям, кроме последнего, и сохраняет их в группе 1. Регулярное выражение ([^ ]) (которое, несмотря на то, что выглядит stackoverflow, похоже, состоит из пробела, за которым следует ([^ ]) ) соответствует пробелу, за которым следует небук, и сохраняет непустую в группе 2.

    \1.\2 заменяет согласованный текст группой 1, за которой следует период, за которым следует группа 2.

  • ta

    Если замещенная команда привела к замене, вернитесь к метке a и повторите попытку.

Совместимость:

  1. Вышеописанное было протестировано на современном GNU sed. Для BSD / OSX sed можно или не нужно использовать:

     sed -E -e :a -e 's/^( *) ([^ ])/\1.\2/' -e ta file 

    В древнем GNU sed нужно использовать -r вместо -E :

     sed -r ':a; s/^( *) ([^ ])/\1.\2/; ta' file 
  2. Вышеизложенное предполагало, что пробелы были пробелами. Если они являются вкладками, вам нужно будет решить, что такое ваш tabstop, и сделать замены соответственно.

Есть два разных способа сделать это в vim.

  1. С регулярным выражением:

     :%s/^\s\+/\=repeat('.', len(submatch(0))) 

    Это довольно просто, но немного подробный. Он использует регистр eval ( \= ) для генерации строки '.' s той же длины, что и количество пробелов в начале каждой строки.

  2. С нормой:

     :%norm ^hviwr. 

    Это гораздо более удобная короткая команда, хотя ее немного сложнее понять. Он визуально выбирает пробелы в начале строки и заменяет весь выбор точками. Если нет ведущего пробела, команда будет терпеть неудачу на ^h потому что курсор пытается выйти из пределов.

    Чтобы увидеть, как это работает, попробуйте ^hviwr. на линии, которая имеет ведущие пространства, чтобы увидеть, как это происходит.

Поскольку вы сказали python :

 #!/usr/bin/env python import re, sys for line in sys.stdin: sys.stdout.write(re.sub('^ +', lambda m: len(m.group(0)) * '.', line)) 

(для каждой строки мы заменяем самый длинный пробег префиксных пространств '^ +' с одинаковой длинной строкой точек, len(m.group(0)) * '.' ).

С конечным результатом:

 $ ./dottify.py <file top f1 f2 f3 ...sub1 f1 f2 f3 ...sub2 f1 f2 f3 ......sub21 f1 f2 f3 ...sub3 f1 f2 f3 

Поскольку вы сказали awk :

 $ awk '{ match($0,/^ +/); p=substr($0,0,RLENGTH); gsub(" ",".",p); print p""substr($0,RLENGTH+1) }' file top f1 f2 f3 ...sub1 f1 f2 f3 ...sub2 f1 f2 f3 ......sub21 f1 f2 f3 ...sub3 f1 f2 f3 

(где для каждой строки мы сопоставляем длинный префикс пробелов с match , извлекаем его с помощью substr , заменяем каждое пространство точкой через gsub и печатаем модифицированный префикс p , за которым следует остальная часть строки ввода (переменные RSTART и RLENGTH заполняются после match() и удерживайте исходное положение и длину совпадающего рисунка).

В awk. Он продолжает заменять первое пространство периодом, в то время как пробел предшествует только периодам:

 $ awk '{while(/^\.* / && sub(/ /,"."));}1' file top f1 f2 f3 ...sub1 f1 f2 f3 ...sub2 f1 f2 f3 ......sub21 f1 f2 f3 ...sub3 f1 f2 f3 

и вот один из perl:

 $ perl -p -e 'while(s/(^\.*) /\1./){;}' file top f1 f2 f3 ...sub1 f1 f2 f3 ...sub2 f1 f2 f3 ......sub21 f1 f2 f3 ...sub3 f1 f2 f3 

Тем не менее, немного продолжительное, но веселое упражнение:

 # Function to count the number of leading spaces in a string # Basically, this counts the number of consecutive elements that satisfy being spaces def count_leading_spaces(s): if not s: return 0 else: curr_char = s[0] if curr_char != ' ': return 0 else: idx = 1 curr_char = s[idx] while curr_char == ' ': idx += 1 try: curr_char = s[idx] except IndexError: return idx return idx 

Наконец, откройте файл и выполните некоторую работу:

 with open('file.txt', 'r') as f: data = [] for i, line in enumerate(f): # Don't do anything to the field names if i == 0: new_line = line.rstrip() else: n_leading_spaces = count_leading_spaces(line) # Impute periods for spaces new_line = ('.'*n_leading_spaces + line.lstrip()).rstrip() data.append(new_line) 

Результаты:

 >>> print('\n'.join(data)) top f1 f2 f3 ...sub1 f1 f2 f3 ...sub2 f1 f2 f3 ......sub21 f1 f2 f3 ...sub3 f1 f2 f3 

Вы также можете сделать это таким образом, что намного проще:

 with open('file.txt', 'r') as f: data = [] for i, line in enumerate(f): # Don't do anything to the field names if i == 0: new_line = line.rstrip() else: n_leading_spaces = len(line) - len(line.lstrip()) # Impute periods for spaces new_line = line.lstrip().rjust(len(line), '.').rstrip() data.append(new_line) 
  • Редактор Bpython-like / IDE?
  • Как свернуть длинные docstrings в исходном коде python в VIM?
  • сортировать по названию в vim
  • Выполнить команду python в vim и получить вывод
  • Generic: команда python в vim?
  • Vim запуск ярлыка
  • vim выделяет все в красном
  • Как решить «требуется поддержка python 2.x» в linux vim, и в моей системе есть python 2.6.6
  • Python - лучший язык программирования в мире.