2011-12-20 5 views
3

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

# should match 
#1234567890 
#123-456-7890 
#123.456.7890 
#(123)456-7890 
#(123) 456-7890 

BEGIN{ 
    regexp="[0-9]{10},[0-9]{3}[-.][0-9]{3}[.-][0-9]{4},\\([0-9]{3}\\) ?[0-9]{3}-[0-9]{4}" 
    len=split(regexp,regs,/,/) 
} 
{for (i=1;i<=len;i++) 
    if ($0 ~ regs[i]) print $0 
} 

Для лучшей читаемости я хотел бы разделить линию regexp="... на несколько линиях, как:

regexp="[0-9]{10} 
     ,[0-9]{3}[-.][0-9]{3}[.-][0-9]{4} 
     ,\\([0-9]{3}\\) ?[0-9]{3}-[0-9]{4}" 

Есть простой способ сделать это в awk?

+1

Я бы подумал, что, начиная с массива regs [] и помещая каждый шаблон в свою собственную ячейку, будет более самодокументированным, то есть 'regs [1] =" [0-9] {10} "' ... .. Я не уверен в том, какая разница между чем-то вроде '($ 0 ~/regex /) AND ($ 0 ~ regs [i])' будет работать. Кроме того, как бы вы предложили управлять изменениями в своем регулярном выражении по мере его увеличения и увеличения (трудно понять, где изменения, возможно, находятся на крайнем правом значении, и что более важно, если вам требуется запятая char ',', то у вас есть изменить свой разделитель! ;-)! Удачи. – shellter

+1

Неправильное выражение в вашем регулярном выражении. 123.456-789 или 123-456.789. но их нет в вашем списке. вам может понадобиться группа. – Kent

+0

Привет, Кент, спасибо вам за внимательный глаз. Могу ли я использовать группировку с формой «$ 0 ~ regs [i]» или мне нужно использовать gensub? – Chris

ответ

0

Как представляется, консенсус заключается в том, что нет простого способа разделить многострочные строки без нарушения awk? Спасибо за другие идеи, но заставьте меня программистом сделать работу компьютера, что мне не нравится. Поэтому я придумал это решение, которое, на мой взгляд, довольно близко к какой-то исполняемой спецификации. Я использую базу и здесь документы и процесс redicrection для создания файлов для AWK на лету:

#!/bin/bash 

# numbers that should be matched 
read -r -d '' VALID <<'valid' 
1234567890 
123-456-7890 
123.456.7890 
(123)456-7890 
(123) 456-7890 
valid 
# regexp patterns that should match 
read -r -d '' PATTERNS <<'patterns' 
[0-9]{10} 
[0-9]{3}\.[0-9]{3}\.[0-9]{4} 
[0-9]{3}-[0-9]{3}-[0-9]{4} 
\([0-9]{3}\) ?[0-9]{3}-[0-9]{4} 
patterns 

gawk --re-interval 'NR==FNR{reg[FNR]=$0;next} 
    {for (i in reg) 
    if ($0 ~ reg[i]) print $0}' <(echo "$PATTERNS") <(echo "$VALID") 

Любые комментарии приветствуются.

1

Ну вы можете хранить регулярное выражение в переменных, а затем присоединиться к ним, например:

awk '{ 
     COUNTRYCODE="WHATEVER_YOUR_CONTRY_CODE_REGEXP" 
     CITY="CITY_REGEXP" 
     PHONENR="PHONENR_REGEX" 
     THE_WHOLE_THING=COUNTRYCODE CITY PHONENR 
     if ($0 ~ THE_WHOLE_THING) { print "BINGO" } 
    }' 

НТН

3
BEGIN { 
    regs[1] = "[0-9]{10}" 
    regs[2] = "[0-9]{3}[-.][0-9]{3}[.-][0-9]{4}" 
    regs[3] = "\\([0-9]{3}\\) ?[0-9]{3}-[0-9]{4}" 
    c = 3 
    } 
{ 
    for (i = 1; i <= c; i++) 
    if ($0 ~ regs[i]) 
     print $0 
    } 

Если ваша реализация AWK поддерживает длину (массив) - использовать его (см Jaypal Singh комментарии ниже):

BEGIN { 
    regs[1] = "[0-9]{10}" 
    regs[2] = "[0-9]{3}[-.][0-9]{3}[.-][0-9]{4}" 
    regs[3] = "\\([0-9]{3}\\) ?[0-9]{3}-[0-9]{4}" 
    } 
{ 
    for (i = 1; i <= length(regs); i++) 
    if ($0 ~ regs[i]) 
     print $0 
    } 

Учитывайте также побочные эффекты вычисленных (динамических) регулярных выражений, см. GNU awk manual для получения дополнительной информации.

+1

+1 ... Хотя я бы изменил 'i <= 3' на' i <= length (regs) ', поскольку он предложит расширяемость, если массив' regs' был позже добавлен с большим количеством 'regexes'. –

+0

Привет @JaypalSingh, хороший момент! Стоит отметить, что length (array) является расширением (т. Е. Он недоступен во всех современных реализациях awk). –

2

Следующая ссылка может содержать ответ, который вы искали:

http://www.gnu.org/software/gawk/manual/html_node/Statements_002fLines.html

Он говорит, что в файлах скриптов AWK или в командной строке определенных оболочек, команды AWK могут быть разбиты на несколько строк в так же, как команды makefile. Просто закончите линию с обратной косой чертой (\), и awk отменит символ новой строки при разборе. В сочетании с неявной конкатенацией строк (по аналогии с C), и решение может быть

BEGIN { 
    regexp = "[0-9]{10}," \ 
      "[0-9]{3}[-.][0-9]{3}[.-][0-9]{4}," \ 
      "\\([0-9]{3}\\)?[0-9]{3}-[0-9]{4}" 
    len = split(regexp, regs, /,/) 
} 

Тем не менее, я бы пользу решения, которое хранит регулярные выражения в массиве непосредственно: это лучше отражает намерение заявления и не заставляет программиста выполнять больше работы, чем требуется. Кроме того, нет необходимости в функции length, так как можно использовать синтаксис foreach. Следует отметить, что массивы в awk похожи на карты на Java или словари на Python, поскольку они не связывают диапазон целочисленных индексов со значениями. Скорее они сопоставляют строковые ключи со значениями. Даже если в качестве ключей используются целые числа, они неявно преобразуются в строку. Таким образом, функция length не всегда предоставляется, поскольку она вводит в заблуждение.

BEGIN { 
    regs[1] = "[0-9]{10}" 
    regs[2] = "[0-9]{3}[-.][0-9]{3}[.-][0-9]{4}" 
    regs[3] = "\\([0-9]{3}\\)?[0-9]{3}-[0-9]{4}" 
} 

{ 
    for (i in regs) {  # i recieves each key added to the regs array 
     if ($0 ~ regs[i]) { 
      print   # by default `print' prints the whole record 
      break   # we can stop finding a regexp 
     } 
    } 
} 

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

0

Я хочу представить свой любимый этому вопросу, так как он еще не упоминался. Я хотел бы использовать простую операцию строки на добавление в AWK, то есть просто оператор по умолчанию между двумя терминами, как умножение в типичных математических обозначениях:

x = x"more stuff" 

добавляет "more stuff" к x и устанавливает новое значение x снова. Таким образом, вы можете написать

regexp = "" 
regexp = regexp"[0-9]{10}" 
regexp = regexp"[0-9]{3}[-.][0-9]{3}[.-][0-9]{4}" 
regexp = regexp"\\([0-9]{3}\\) ?[0-9]{3}-[0-9]{4}" 

Для управления дополнительных символов разделения, как переводы строк между фрагментами большинство языков я знаю и AWK тоже можно использовать массив присоединиться и методы раскола, чтобы сделать строку из массива и преобразовать обратно в строку в массив, без потери исходной структуры массива (например, символ новой строки маркеры):

i = 0 
regexp[i++] = "[0-9]{10}" 
regexp[i++] = "[0-9]{3}[-.][0-9]{3}[.-][0-9]{4}" 
regexp[i++] = "\\([0-9]{3}\\) ?[0-9]{3}-[0-9]{4}" 

regstr = join(regexp, ",") Использование добавить раскол «» вы использовали. Конечно, в awk нет функции соединения, но я думаю, что это очень просто для реализации, зная, что операция добавления строки выше.

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