Bash, awk и / или sed для очистки строки с помощью специального форматирования

В сценарии, над которым я работаю, мне нужно очистить строку до нужного мне формата.

Структура каждой строки: (почтовый индекс, название улицы, номер, добавочный номер):

  • 4 цифры, 2 буквы (почтовый индекс) Если нет совпадений, нет результата
  • строка символов (название улицы) может иметь любой символ
  • строка цифр (число)

В конце концов последовал

  • строка символов (расширение) может иметь любой вид символа и не всегда присутствует. Цифра отделяется от числа тире, пробелом или чем-то еще.

Результирующая строка должна быть 4 цифры, 2 буквы, номер и, в случае расширения, за которым следует x, а также буква или цифра добавочного номера

Ниже приведены некоторые примеры:

  • 1019RXJavakade254 -результат: 1019RX254
  • 1019PGBogortuin50 -результат: 1019PG50
  • 1079-йEemsstraat34-II -результат: 1079TH34xII
  • 1066EC1eLouwesweg6 - результат: 1066EC6
  • 1019LCKNSM-laan193 -результат: 1019LC193
  • 1019WZScheepstimmermanstraat74 -результат: 1019WZ74
  • 2288EASirWinstonChurchillaan275-F126 -результат: 2288EA275xF126
  • 1056 ГцMaartenHarpertszoonTrompstraat12-3hg -результат: 1056 Гц
  • 1092GRLaing'snekstraat15G -результат: 1092GR15xG
  • F-30700RueduLavoir1 -результат: ничего такого

Я начал с

echo "1019RXJavakade254" | awk '{print substr($0,0,6)}'

чтобы получить почтовый индекс и после этого я думаю, что мне следует использовать «печатное совпадение», но я не могу получить его прямо оттуда.

Строки передаются индивидуально и используются на следующем шаге скрипта. Первоначально они поступают из файла csv, но (комбинация) столбцов, из которых поступает строка, всегда различаются. Первая часть скрипта обрабатывает это и создает эту исходную строку. Результирующая строка будет помещена обратно в столбец, который я могу добавить в качестве последнего столбца в исходный файл csv.

Мне известно о проблемах, связанных с числами после первых 6 символов и наличием расширения. Поэтому, на мой взгляд, рабочий процесс должен быть примерно таким: первые 6 символов должны быть 4 цифрами, 2 буквами, если не общий результат, пустой. Пропустите символы 7 и 8 и возьмите первую группу цифр, которые вы встретите после символа 8, это номер, а все остальное после этого является расширением. Расширение никогда не начинается с цифры. Только в случае расширения между ними стоит х. В расширении не должно быть буквенно-цифровых символов.

Этого должно хватить на большую часть, у остальных будет задержка доставки :)


Решено

@kvantour Спасибо за ответ. Я немного изменил код, чтобы получить не заглавные буквы. Результатом является часть более крупного приложения, которое запускается без присмотра на Xserve здесь, в компании. Итак, код, который я использую сейчас, это

set KixCodeSourceClean to do shell script "echo " & KixCodeSource & " | awk '/^[0-9]{4}[a-zA-Z]{2}.+[0-9]+[- ].+$/{match(substr($0,8),/[0-9]+[- ].+$/);s=substr($0,7+RSTART,RLENGTH); sub(/[- ]/,\"x\",s);print substr($0,1,6)s;next} /^[0-9]{4}[a-zA-Z]{2}.+[0-9]+[a-zA-Z].*$/{match(substr($0,8),/[0-9]+[a-zA-Z].*$/);s=substr($0,7+RSTART,RLENGTH);match(s,/[0-9]+/);print substr($0,1,6)substr(s,1,RLENGTH)\"x\"substr(s,RLENGTH+1);next} /^[0-9]{4}[a-zA-Z]{2}.+[0-9]+$/{ match(substr($0,8),/[0-9]+$/);s=substr($0,7+RSTART);print substr($0,1,6)s;next}'"

Он работает отлично и представляет собой единственную строчку, которую я предпочитаю в данном случае. Я часто использую этот метод. Прыгать в Applescript и выходить из него и использовать оболочку unix для более быстрого решения задач.

Эти строковые переменные передаются в ваш скрипт по отдельности или они берутся из файла сразу (например, каждая в отдельной строке)?

Tom Fenech 24.07.2018 10:15

Строки передаются индивидуально и используются на следующем шаге.

JB Veenstra 24.07.2018 10:42

Проблемы возникают с такими именами, как "1066EC1eLouwesweg6-F"

kvantour 24.07.2018 10:52

Вам нужно уточнить расширение. Вы говорите, что это разделено «тире, пробелом или чем-то еще», но у меня такое чувство, что это «что-то еще» будет источником проблем.

Tom Fenech 24.07.2018 10:53

@TomFenech Также не забывайте его предпоследний пример, который показывает расширение без чего-либо.

kvantour 24.07.2018 10:54

@Tom and Kvantour Мне известно о проблемах, связанных с числами после первых 6 символов и наличием расширения. Поэтому, на мой взгляд, рабочий процесс должен быть примерно таким: первые 6 символов должны быть 4 цифрами, 2 буквами, если не общий результат, пустой. Пропустите символы 7 и 8 и возьмите первую группу цифр, которые вы встретите после символа 8, это номер, а все остальное после этого является расширением. Расширение никогда не начинается с цифры. Только в случае расширения между ними стоит х. В расширении не должно быть буквенно-цифровых символов.

JB Veenstra 24.07.2018 11:10

@ user6802941 Я предлагаю вам отредактировать эту информацию в своем вопросе, чтобы сделать ее как можно более ясной.

Tom Fenech 24.07.2018 11:28

@JBVeenstra не забывайте Синт Витушолт 2е Лаан в Виндшотене и А в Оттоланде. Пропуск первых двух может не решить проблему.

kvantour 24.07.2018 11:55
редактировать ваш вопрос, чтобы предоставить сжатый, проверяемый образец ввода и ожидаемый результат в формате, в котором мы можем просто скопировать / вставить их, чтобы проверить потенциальное решение, без необходимости редактировать их для удаления форматирования и т. д. Используйте кнопку редактора {} для правильного форматирования (или отступ каждой строки на 4 символа вручную).
Ed Morton 24.07.2018 13:17
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
9
248
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

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

$ str = "1066EC1eLouwesweg6"
$ sed -r 's/(^[0-9]{4}[A-Z]{2})..[^0-9]*(.*)/\1\2/' <<< "$str" | sed 's/-/x/' | sed -r '/[^x]/ s/(.*[0-9]+)([A-Z]+$)/\1x\2/'
1066EC6

Краткое объяснение,

  1. sed -r 's/(^[0-9]{4}[A-Z]{2})..[^0-9]*(.*)/\1\2/' <<< "$str": сначала отфильтровывает название улицы.
  2. sed 's/-/x/': замените '-' на 'x', если существует
  3. sed -r '/[^x]/ s/(.*[0-9]+)([A-Z]+$)/\1x\2/': если результат до сих пор не существует "x", добавьте "x" между цифрами и алфавитами.
Ответ принят как подходящий

Я имел в виду принцип исключения, в котором мы проверяем одну возможность за другой:

  1. Адреса формы NNNNXXabc123efgMMM-SUF и NNNNXXabc123efgMMM SUF
  2. Адреса формы NNNNXXabc123efgMMMSUF
  3. Адреса формы NNNNXXabc123efgMMM

Проблема, однако, в том, что SUF может быть чем угодно, а abc123efg - чем угодно. Как следствие, пример «1066EC1eLouwesweg6» будет соответствовать второму случаю.

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

  • Ir. Г-н д-р ван Вотершут ван дер Грахтстраат в Херлене (только давно)
  • Марга Кломпелаан и Groot-Brittanniëstraat в Неймвегене (диакритические знаки)
  • 1e en 2e Anjeliers-dwarsstraat в Амстердаме (начиная с цифр)
  • Синт Витушолт 2е Лаан в Винсхотене (цифры посередине)
  • 's-Gravelandseweg в Hilversum (начиная с ')
  • А и B в Оттоланде (слишком короткие)

Таким образом, нет даже условия относительно длины названия улицы, за исключением того, что если оно состоит из одного символа, это буква.

Итак, это дало мне следующий AWK:

{gsub(/\r/,"",$0)}  # removes `\r` if any
/^[0-9][0-9][0-9][0-9][A-Z][A-Z].+[0-9]+[- ].+$/{match(substr($0,8),/[0-9]+[- ].+$/);s=substr($0,7+RSTART,RLENGTH); sub(/[- ]/,"x",s);print substr($0,1,6)s;next}
/^[0-9][0-9][0-9][0-9][A-Z][A-Z].+[0-9]+[a-zA-Z].*$/{match(substr($0,8),/[0-9]+[a-zA-Z].*$/);s=substr($0,7+RSTART,RLENGTH);match(s,/[0-9]+/);print substr($0,1,6)substr(s,1,RLENGTH)"x"substr(s,RLENGTH+1);next}
/^[0-9][0-9][0-9][0-9][A-Z][A-Z].+[0-9]+$/{ match(substr($0,8),/[0-9]+$/);s=substr($0,7+RSTART);print substr($0,1,6)s;next}

И в этом входном файле:

1019RXJavakade254
1019PGBogortuin50
1079THEemsstraat34-II
1066EC1eLouwesweg6
1019LCKNSM-laan193
1019WZScheepstimmermanstraat74
2288EASirWinstonChurchillaan275-F126
1056HZMaartenHarpertszoonTrompstraat12-3hg
1092GRLaing'snekstraat15G
F-30700RueduLavoir1

Это дало мне следующий результат:

1019RX254
1019PG50
1079TH34xII
1066EC6
1019LC193
1019WZ74
2288EA275xF126
1056HZ12x3hg
1092GR15xG

Как вы заметили, последний не совпадает!

Однако я не могу заверить вас, что это сработает на 100%.

fun fact: In Ottoland, you can travel from A to B by crossing a bridge of 10m.

Это (с использованием GNU awk для 3-го аргумента для match() и gensub()) даст ожидаемый результат из предоставленных вами входных данных:

$ cat tst.awk
match($1,/^([0-9]{4}[[:alpha:]]{2})(..[^0-9]+)(.*)/,a) {
    if ( ! sub(/[^[:alnum:]]/,"x",a[3]) ) {
        a[3] = gensub(/([0-9])([[:alpha:]])/,"\\1x\\2",1,a[3])
    }
}
{
    tgt = (1 in a ? a[1] a[3] : "nothing")
    print tgt, (tgt == $NF ? "succ" : "fail")
}

$ awk -f tst.awk file
1019RX254 succ
1019PG50 succ
1079TH34xII succ
1066EC6 succ
1019LC193 succ
1019WZ74 succ
2288EA275xF126 succ
1056HZ12x3hg succ
1092GR15xG succ
nothing succ

Это не удастся, если цифра может появиться в названии улицы где угодно, кроме первых двух символов.

Вышеупомянутое было выполнено для этого входного файла и печатает succ / fail после каждого результата в зависимости от того, соответствует ли результат ожидаемому результату из последнего поля входного файла:

$ cat file
1019RXJavakade254 -result: 1019RX254
1019PGBogortuin50 -result: 1019PG50
1079THEemsstraat34-II -result: 1079TH34xII
1066EC1eLouwesweg6 -result: 1066EC6
1019LCKNSM-laan193 -result: 1019LC193
1019WZScheepstimmermanstraat74 -result: 1019WZ74
2288EASirWinstonChurchillaan275-F126 -result: 2288EA275xF126
1056HZMaartenHarpertszoonTrompstraat12-3hg -result: 1056HZ12x3hg
1092GRLaing'snekstraat15G -result: 1092GR15xG
F-30700RueduLavoir1 -result: nothing

Другие вопросы по теме