6
\$\begingroup\$

Table of contents

  • Preface
  • Synopsis
    • Notation
    • For First fsed
    • For Second fsed
  • Challenge
    • Task for first language
    • Task for second language
    • Input restrictions
    • Other rules
  • Test cases
  • Further readings
  • Sample implementation for second task

Preface

As a (formerly) serious shell(script) enthusiast I know two useful utilities:

  • fsed utility, developed by ShellShoccar-jpn
  • fsed utility, developed by Universal Shell Programming Lab as a part of Open-usp-Tukubai (also known as Unicage tools)

They have incompatible synopsis.

Synopsis

Notation

(0) I am using utility synopsis syntax, which is represented by space-delimined list of strings, to describe their specifications:

(0-1) part surrounded by the braces means it is optional part, and

(0-2) the pipe | inside the braces means that one of two items on both sides of the pipe can be used but not both, and

(0-3) the ellipsis ... means that the part can be repeated one or more times.

For First fsed

(1) The usage of former utility is:

fsed pattern replacement [file...]

where

  • (1-1) pattern is a nonempty string consists of any characts except newline, and
  • (1-2) replacement is any string, and
  • (1-3) file, which can occur for zero or more times, is any string.

For Second fsed

(2) The latter usage is:

fsed [-e|-i] s-command [file]
fsed [[-e|-i] s-command ...] -e s-command [file]
fsed [[-e|-i] s-command ...] -i s-command [file]
fsed [[-e|-i] s-command ...] s-command file

where

  • (2-1) -e or -i option, (2-1-2) which can be used exclusively but not both at same time, applies to each following s-command, and
  • (2-2) file, (2-2-1) either (2-2-1a) a hyphen - or (2-2-1b) a string who starts with a character other than hyphen, (2-2-2) must be specified explicitly when in case of fourth usage: (2-2-3a) multiple s-commands are specified and (2-2-3b) the last s-command has no -e or -i options.

(2-3) The s-command looks like these:

s/pattern/replacement/
s,/,-,42
s/New York/California/g

(2-3-1) The s-command is a list of four strings delimited by a character;

  • (2-3-2) the first part must be the letter s, and
  • (2-3-3) the second and third parts are any strings except they cannot contain the delimiter character specified by (2-3-1), and
  • (2-3-4) the fourth and last part is either
    • (2-3-4a) empty, or
    • (2-3-4b) a decimal representation of a positive integer, or
    • (2-3-4c) the letter g.

Challenge

Write a polyglot in two languages of your choice to solve different tasks for each language.

Task for first language

Given a list of strings (which is arguments for the first fsed utility), decide whether it meets its usage. I.e. return true if input meets all conditions as follows, and return false otherwise:

  1. has two or more items,
  2. first item has one or more characters, and
  3. first item has no newlines.

Task for second language

Similar to previous task for second fsed.

Input restrictions

Input strings shall be newlines and characters of ASCII printables except backslash \.

Other rules

. Standard I/O. Standard loopholes. .

Test cases

Line-by-line. Like JSON or Python syntax.

Falsey for first task

[]
[""]
["",""]
["","",""]
["\n","","-","bar"]
["foo\nbar","baz\nbaz","foo"]

Truthy for first task

["foo",""]
["foo","bar","-","--help"]
["foo bar","baz\nbaz","quux"]
["F","","","",""]

Falsey for second task

[]
["foo"]
["s\nAmerica\nCanada\n3","Singapore.txt","Jamaica.mp3"]
["s(p)(q)(9","-e"]
["s"]
["s/"]
["s/foo"]
["s/foo/bar"]
["S!foo!bar!"]
["s!foo!bar!0","file.lol"]
["s!foo!bar!-1","file.lol"]
["s!foo!bar!!","file.lol"]

Truthy for second task

["s/foo//"]
["s/foo/bar/"]
["s/foo\nbar/baz/"]
["s\nAmerica\nCanada\n3","Singapore.txt"]
["s/alpha/Alpha/1","s/bravo/Bravo/3","data1.txt"]
["s/foo/FOO/g","data2.txt"]
["-e","s/^[f]oo+$/FOO/","data3.txt"]
["-i","s/intercal/DO.1<-#32/g","data4.txt"]
["s/intercal/DOREADOUT.1/42","-i","s/brainfuck/++++++[->+++++++<]./1","data5.txt"]
["s,///,/ab/bba/Abba,7","data6.txt"]

Further readings

當仲寛哲/山崎裕詞/熊谷章/熊野憲辰/木ノ下勝郎, "ユニケージ原論".

USP研究所, "実践ユニケージ開発手法01 コマンド学習編"

USP研究所, "実践ユニケージ開発手法02 シェルスクリプト学習編"

USP研究所, "実践ユニケージ開発手法03 Webアプリケーション編"

松浦智之, "すべてのUNIXで20年動くプログラムはどう書くべきか デプロイ・保守に苦しむエンジニア達へ贈る[シェルスクリプトレシピ集]"

Sample implementation for second task

In Python 3, 1810 bytes

from typing import List, Tuple

def isUnicageFsed(args: List[str]) -> Tuple[bool, str]:
    filename: str = "-"
    s_commands: List[Tuple[str, str]] = []

    while len(args) > 0:
        if args[0].startswith("-") and len(args[0]) > 1:
            is_valid_flag = args[0] in "-e", "-i"
            if not is_valid_flag:
                return (False, f"invalid flag: {args[0]}")
            try:
                s_commands.append((args[0], args[1]))
            except IndexError:
                return (False, f"missing s-command for flag {args[0]}")
            args = args[2:]
        else:
            s_commands.append((None, args[0]))
            args = args[1:]

    if len(s_commands) > 1:
        (flag, maybe_filename) = s_commands[-1]
        if not flag:
            filename = maybe_filename
            s_commands.pop()
    elif len(s_commands) < 1:
        return (False, "missing s-command")

    rules: List[Tuple[str, Tuple[str, str, int | str | None]]] = []
    for (flag, s_command) in s_commands:
        try:
            delimiter = s_command[1]
        except IndexError:
            return (False, f"incomplete s-command: {s_command}")
        try:
            (s, pat, rep, s_flag) = s_command.split(delimiter, 3)
        except ValueError:
            return (False, f"incomplete s-command: {s_command}")
        if s != "s":
            return (False, f"not s-command: {s_command}")
        try:
            s_flag = int(s_flag)
            if s_flag <= 0:
                return (False, f"invalid field for s-command: {s_flag}")
        except ValueError:
            is_flag = not s_flag or s_flag == "g"
            if not is_flag:
                return (False, f"invalid flag for s-command: {s_flag}")
        rules.append((flag, (pat, rep, s_flag)))

    return (True, None)

Try it online!

\$\endgroup\$
5
  • \$\begingroup\$ sandbox \$\endgroup\$ Commented Mar 12, 2025 at 12:16
  • \$\begingroup\$ When doing challenge 2, may we use different programming languages for the two programs? \$\endgroup\$ Commented Mar 18, 2025 at 11:18
  • \$\begingroup\$ Your example code in TIO doesn't compile: Variable not in scope: inList :: [[Char]] -> p \$\endgroup\$ Commented Mar 18, 2025 at 11:22
  • \$\begingroup\$ @corvus_192 1. Never thought of that idea for challenge 2; at first I was thinking to be answered with same language; if I allowed polyglot then the winning criterion would be chaos. 2. I'm sorry for not being able to parse that test case into usable data structure; submitted that as is \$\endgroup\$ Commented Mar 19, 2025 at 0:26
  • \$\begingroup\$ Am confused to read (2-2); at least main part itself of reference implementation should not call error; why did I make this task? \$\endgroup\$ Commented Apr 11 at 11:45

0

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.