LINUX.ORG.RU

Bash скрипт для обработки текстового файла

 ,


0

1

Доброго времени суток.
Я составляю словарь орфографии для hunspell. На данном этапе я имею файл аффиксов и файл инфинитивов (с флагами). Однако, из-за «издержек производства» в словаре проскакивают дубли, но с разными флагами. Например.

автоинспектор/1,5,15,20,25
автоинспектор/1,5,15,20,29
адрес/1,5,15,20,25
адрес/1,5,15,20,29
амбарище/1,5,15,25
амбарище/1,5,15,27
...

Из этого нужно получить следующее:
автоинспектор/1,5,15,20,25,29
адрес/1,5,15,20,25,29
амбарище/1,5,15,25,27
...

т.е. убрать слова-дубли, но «сложить» флаги

Написал такой скрипт:
#!/bin/bash

input_file="d.txt"
output_file="out.txt"

previous_word="none"
previous_flags_array=()

for line in `cat $input_file` ; do
	IFS="/"
	set -- $line
	current_word=$1
	flags=$2
	IFS=","
	set -- $flags
	current_flags_array=($1 $2 $3 $4 $5)
    if [ $previous_word == "none" ] ; then
		previous_word=$current_word
		previous_flags_array=("${current_flags_array[@]}")
	else
		if [ $previous_word == $current_word ] ; then
			previous_flags_array=("${previous_flags_array[@]}" "${current_flags_array[@]}")
		else
			sorted_final_flags=($(echo "${previous_flags_array[@]}" | tr ' ' '\n' | sort -u | tr '\n' ' '))
			echo "$previous_word"/"${sorted_final_flags[@]}" >> $output_file
			previous_word=$current_word
			previous_flags_array=("${current_flags_array[@]}")
		fi
	fi
done


Есть два вопроса:
1. Скрипт не экспортирует последнее обрабатываемое слово. Как задать, чтобы при достижении EOF также выполнялось:
sorted_final_flags=($(echo "${previous_flags_array[@]}" | tr ' ' '\n' | sort -u | tr '\n' ' '))
echo "$previous_word"/"${sorted_final_flags[@]}" >> $output_file


2. Данный скрипт написан для 5 позиционных параметров (соответственно 5 флагам). Как задать так, чтобы работало и с большим, и с меньшим количеством параметров (флагов)?

Немножко плохого кода тебе в тему

#!/usr/bin/env python3

with open("test-input.txt") as input_file:
    input_data = input_file.readlines()

dict = {}

for line in input_data:
    dict_key, dict_val = line.split("/")
    dict_val_list = list(map(int, dict_val.replace("\n", "").split(",")))
    try:
        if dict[dict_key]:
            new_value = sorted(list(set(dict[dict_key] + dict_val_list)))
            dict[dict_key] = new_value
    except KeyError:
        dict[dict_key] = dict_val_list

with open("test-output.txt", "w") as output_file:
    for k, v in dict.items():
        output_file.write("{}/{}\n".format(k, ",".join(str(x) for x in v)))
Yorween ()
Ответ на: комментарий от beresk_let

Вот тебе альтернативный вариант, но тоже на питоне.

#!/usr/bin/env python3

from sys import stdin, stdout
from typing import Set, Dict, Iterable, Generator, TextIO
from argparse import ArgumentParser, FileType

WORD_SEPARATOR = '/'
KEYS_SEPARATOR = ','

parser = ArgumentParser()
parser.add_argument('input', nargs='?', type=FileType('r'),
                    default=stdin, help='input file')
parser.add_argument('output', nargs='?', type=FileType('w'),
                    default=stdout, help='output file')


def get_parsed_data(data: Iterable[str]) -> Dict[str, Set[str]]:
    parsed_data = {}

    for line in data:
        if WORD_SEPARATOR in line:
            word, keys = line.split(WORD_SEPARATOR)[:2]
            keys = keys.strip().split(KEYS_SEPARATOR)
            parsed_data.setdefault(word, set()).update(keys)

    return parsed_data


def gen_output(data: Dict[str, Iterable[str]]) -> Generator[str, None, None]:
    for word, keys in data.items():
        keys = sorted(map(int, keys))
        keys = KEYS_SEPARATOR.join(map(str, keys))
        line = WORD_SEPARATOR.join((word, keys))

        yield line


def main(input_file: TextIO, output_file: TextIO):
    input_data = input_file.readlines()
    parsed_data = get_parsed_data(input_data)
    output_data = sorted(gen_output(parsed_data))
    output_file.write('\n'.join(output_data))


if __name__ == '__main__':
    args = parser.parse_args()
    main(args.input, args.output)

beresk_let ★★★★ ()

Ну нате.

#!/usr/bin/env bash

input_file="d.txt"
output_file="out.txt"
declare -i -a fa2 fa
declare -i i j ni ni1 t vi
previous_word=

exec > "$output_file"

make_out() {
	local i l
	for i; do l+=${l:+,}$i; done
	echo "$previous_word/$l"
}

while IFS=/ read current_word flags; do
	if [[ $previous_word == "$current_word" ]]; then
		IFS=, read -a fa2 <<< "$flags"
		# add uniq flags
		for i in ${fa[*]}; do
			for j in "${!fa2[@]}"; do
				[[ i -eq fa2[j] ]] && fa2[j]=-1
			done
		done
		for j in ${fa2[*]}; do
			[[ j -ne -1 ]] && fa+=(j)
		done
	else
		if [[ $previous_word ]]; then
			# sort
			ni=${#fa[@]}
			ni1=ni-1
			for ((i=0; i<ni1; i++)); do
				vi=fa[i]
				for ((j=i+1; j<ni; j++)); do
					if [[ fa[j] -lt vi ]]; then
						t=fa[j]
						fa[j]=vi
						vi=t
					fi
				done
				fa[i]=vi
			done

			make_out "${fa[@]}"
		fi
		previous_word=$current_word
		IFS=, read -a fa <<< "$flags"
	fi
done < "$input_file"

[[ $previous_word ]] && make_out "${fa[@]}"

vodz ★★★★ ()
Ответ на: комментарий от sspphheerraa

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

#!/usr/bin/env bash

input_file="d.txt"
output_file="out.txt"
declare -i -a fa
declare -i i j
declare pw word flags

exec > "$output_file"

make_out() {
	if [[ $pw ]]; then
		local l
		local -i n=${#fa[@]} vi t
		# sort
		for ((i=0; i<n; i++)); do
			vi=fa[i]
			for ((j=i+1; j<n; j++)); do
				if [[ fa[j] -lt vi ]]; then
					t=fa[j]
					fa[j]=vi
					vi=t
				fi
			done
			l+=${l:+,}$vi
		done
		echo "$pw/$l"
		fa=()
	fi
	pw=$1
}

while IFS=/ read word flags; do
	[[ $pw != "$word" ]] && make_out "$word"
	# add uniq flags
	while read -d ',' j; do
		for i in ${fa[*]}; do
			[[ i -eq j ]] && continue 2
		done
		fa+=(j)
	done <<< "$flags,"
done < "$input_file"

make_out

vodz ★★★★ ()
Ответ на: комментарий от Yorween
    try:
        if dict[dict_key]:
            new_value = sorted(list(set(dict[dict_key] + dict_val_list)))
            dict[dict_key] = new_value
    except KeyError:
        dict[dict_key] = dict_val_list

Кошмар какой.

if dict_key in dict
И больше не надо оборачивать if в try.

Да и непонятно, зачем гонять set в list и обратно, когда можно это сделать один раз при выводе, а в словаре держать только set.

knovich ()
Последнее исправление: knovich (всего исправлений: 1)