Если я правильно понял, вы хотите проверить, имеет ли второй столбец определенный алфавит, если да, попробуйте ниже awk
скрипт, который сообщит, какой из них существует с соответствующим количеством, а какой нет с "NOT FOUND!"
замечание.
awk -v alphabet="$(printf "%s" {a..z})" 'BEGIN{ split(alphabet, arr, "") }
{ chrs[$2]++ } END{ for(y in chrs) for(x in arr)
{ if(arr[x] in chrs) {print y, chrs[y]; delete arr[x]; break }
else{ print arr[x]" NOT FOUND!"; delete arr[x] }
}
}' infile
Выход:
w 1
z 3
a 1
b 1
c 1
f NOT FOUND!
g NOT FOUND!
h NOT FOUND!
i NOT FOUND!
j NOT FOUND!
k NOT FOUND!
l NOT FOUND!
m NOT FOUND!
n NOT FOUND!
o NOT FOUND!
p NOT FOUND!
q NOT FOUND!
r NOT FOUND!
s NOT FOUND!
t NOT FOUND!
u NOT FOUND!
v NOT FOUND!
d 1
x NOT FOUND!
y NOT FOUND!
e 1
Следующая awk
программа должна работать. Он ищет (... )
элементов в каждой строке и проверяет, соответствуют ли они «автор (с ), год» или «автор (с )1 год1, автор (с )2 год2,..." узор. Если да, то создается команда цитирования и заменяется группа (... )
; в противном случае он оставляет группу как есть.
#!/usr/bin/awk -f
# This small function creates an 'authorYYYY'-style string from
# separate author and year fields. We split the "author" field
# additionally at each space in order to strip leading/trailing
# whitespace and further authors.
function contract(author, year)
{
split(author,auth_fields," ");
auth=tolower(auth_fields[1]);
return sprintf("%s%4d",auth,year);
}
# This function checks if two strings correspond to "author name(s)" and
# "year", respectively.
function check_entry(string1, string2)
{
if (string1 ~ /^ *([[:alpha:].-]+ *)+$/ && string2 ~ /^ *[[:digit:]]{4} *$/) return 1;
return 0;
}
# This function creates a 'citation' command from a raw element. If the
# raw element does not conform to the reference syntax of 'author, year' or
# 'author1 year1,author2 year2,...', we should leave it "as is", and return
# a "0" as indicator.
function create_cite(raw_elem)
{
cite_argument=""
# Split at ','. The single elements are either name(list) and year,
# or space-separated name(list)-year statements.
n_fields=split(raw_elem,sgl_elem,",");
if (n_fields == 2 && check_entry(sgl_elem[1],sgl_elem[2]))
{
cite_argument=contract(sgl_elem[1],sgl_elem[2]);
}
else
{
for (k=1; k<=n_fields; k++)
{
n_subfield=split(sgl_elem[k],subfield," ");
if (check_entry(subfield[1],subfield[n_subfield]))
{
new_elem=contract(subfield[1],subfield[n_subfield]);
if (cite_argument == "")
{
cite_argument=new_elem;
}
else
{
cite_argument=sprintf("%s,%s",cite_argument,new_elem);
}
}
else
{
return 0;
}
}
}
cite=sprintf("\\{%s}",cite_argument);
return cite;
}
# Actual program
# For each line, create a "working copy" so we can replace '(...)' pairs
# already processed with different text (here: 'X... Y'); otherwise 'sub'
# would always stumble across the same opening parentheses.
# For each '(... )' found, check if it fits the pattern. If so, we replace
# it with a 'cite' command; otherwise we leave it as it is.
{
working_copy=$0;
# Allow for unmatched ')' at the beginning of the line:
# if a ')' was found before the first '(', mark is as processed
i=index(working_copy,"(");
j=index(working_copy,")");
if (i>0 && j>0 && j<i) sub(/\)/,"Y",working_copy);
while (i=index(working_copy,"("))
{
sub(/\(/,"X",working_copy); # mark this '(' as "already processed
j=index(working_copy,")");
if (!j)
{
continue;
}
sub(/\)/,"Y",working_copy); # mark this ')', too
elem=substr(working_copy,i+1,j-i-1);
replacement=create_cite(elem);
if (replacement != "0")
{
elem="\\(" elem "\\)"
sub(elem,replacement);
}
}
print $0;
}
Вызовите программу с помощью
~$ awk -f transform_citation.awk input.tex
Обратите внимание , что программа ожидает, что ввод будет "достаточно" правильно -сформирован, т. е. все скобки в строке должны быть совпадающими парами (, хотя одна закрывающая скобка в начале строки разрешена для, а несовпадающие открывающие круглые скобки будут игнорироваться ).
Заметьте также , что некоторые из синтаксиса выше требуют GNU awk. Чтобы быть переносимым на другие реализации, замените
if (string1 ~ /^ *([[:alpha:].-]+ *)+$/ && string2 ~ /^ *[[:digit:]]{4} *$/) return 1;
с
if (string1 ~ /^ *([a-zA-Z.-]+ *)+$/ && string2 ~ /^ *[0123456789][0123456789][0123456789][0123456789] *$/) return 1;
и убедитесь, что вы установили языковой стандарт сортировки на C
.