строковая константа форматирования для удобства чтения - PullRequest
3 голосов
/ 21 декабря 2011

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

# 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?

Ответы [ 5 ]

3 голосов
/ 21 декабря 2011
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 для получения дополнительной информации.

2 голосов
/ 24 августа 2012

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

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.Это необходимо, если каждая запись должна быть напечатана только один раз, даже если могут совпадать несколько регулярных выражений.

1 голос
/ 21 декабря 2011

Кажется, что консенсус заключается в том, что не существует простого способа разделения многострочных строк без нарушения awk?Спасибо за другие идеи, но заставляю меня как программиста выполнять работу за компьютером, что мне не нравится.Поэтому я пришел к этому решению, которое, на мой взгляд, довольно близко к своего рода исполняемой спецификации.Я использую базовые и здесь документы и обрабатываю редирект для создания файлов для 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 голос
/ 21 декабря 2011

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

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" }
     }'

HTH

0 голосов
/ 16 декабря 2017

Я хочу представить моего фаворита на этот вопрос, так как он еще не был упомянут. Мне нравится использовать простую операцию добавления строки в 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 нет функции соединения, но я думаю, что это очень просто реализовать, зная операцию добавления строки выше.

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

...