├── LICENSE ├── README.md ├── Run.dyalog └── quadrs /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Adám Brudzewsky 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # QuadR and QuadS 2 | 3 | ## Introduction 4 | QuadR and QuadS are golfing languages which each are barely more than thin covers for [Dyalog APL](https://www.dyalog.com/)'s ⎕R [Replace operator](http://help.dyalog.com/16.0/Content/Language/System%20Functions/r.htm) and ⎕S [Search operator](http://help.dyalog.com/16.0/Content/Language/System%20Functions/r.htm). QuadR and QuadS code can in fact easily be translated to normal Dyalog APL. See [Arguments](#arguments) for information on how to do that. 5 | 6 | ⎕R and⎕S are PCRE based, but enhanced by Dyalog to include application of custom regular expressions-style transformations and arbitrary APL code (including preservation of information from call to call) on each match. 7 | 8 | Feel free to contact me, [Adám](https://stackexchange.com/users/3114363/ad%C3%A1m), in Stack Exchange's [APL chat room](https://chat.stackexchange.com/rooms/52405/apl) to learn more about QuadR, QuadS, and Dyalog APL. 9 | 10 | ## User guide 11 | 12 | [Try It Online](https://tio.run/#home) is a code testing website for many programming languages, both practical and recreational ones, made by Stack Exchange user [Dennis](https://codegolf.stackexchange.com/users/12012). The following describes the relevant fields when using [QuadR on TIO](https://tio.run/#quadr) and [QuadS on TIO](https://tio.run/#quads). 13 | 14 | ### Code 15 | In the simple case, the number of lines determines how the lines are used. If there are an even number of lines, the first half of the lines are *search patterns* (the left operand) while the last half of the lines are *transformation patterns* (the right operand). If there are an odd number of lines, all but the last one are search patterns and the last one is a common transformation pattern for all of the search patterns. (See the last paragraph in this section for an exception to this odd/even rule.) If there is only one non-function line, it will be used as transformation pattern, and the search pattern will be an empty string. 16 | 17 | See [PCRE Regular Expression Syntax Summary](http://help.dyalog.com/16.0/Content/Language/Appendices/PCRE%20Regular%20Expression%20Syntax%20Summary.htm) and [PCRE Regular Expression Details](http://help.dyalog.com/16.0/Content/Language/Appendices/PCRE%20Regular%20Expression%20Details.htm) for details about the search patterns, and [the ⎕R documention](http://help.dyalog.com/16.0/Content/Language/System%20Functions/r.htm) under **Transformation pattern** for details about transformation patterns. 18 | 19 | If the last line includes the character `⍵` (U+2375; APL Functional Symbol Omega), all preceding code lines are search patterns and the last line is a *transformation function* in the form of a [Dyalog APL dfn](http://help.dyalog.com/16.0/Content/Language/Defined%20Functions%20and%20Operators/DynamicFunctions/Dynamic%20Functions%20and%20Operators.htm). The function body will be wrapped in curly braces and multiple statements must be separated by diamonds (`⋄`) rather than newlines, as the function must stay on one line. References to members of the transformation function's argument (a namespace) can optionally be shortened as follows: 20 | 21 | | Short | Full name | 22 | | :---: | ------- | 23 | | `⍵B` | `⍵.Block` | 24 | | `⍵b` | `⍵.BlockNum` | 25 | | `⍵P` | `⍵.Pattern` | 26 | | `⍵p` | `⍵.PatternNum` | 27 | | `⍵M` | `⍵.Match` | 28 | | `⍵O` | `⍵.Offsets` | 29 | | `⍵L` | `⍵.Lengths` | 30 | | `⍵N` | `⍵.Names` | 31 | 32 | QuadR will format and ravel (flatten) the result of the transformation function before returning its result to ⎕R, since ⎕R's transformation function must return a simple character vector (string). See [the ⎕R documention](http://help.dyalog.com/16.0/Content/Language/System%20Functions/r.htm) under **Transformation Function** for further details about transformation functions. 33 | 34 | Optionally, the code may have one or more leading lines of post-processing dfn bodies. Like the transformation function, these are identified by the presence of `⍵`, and curly braces are added automatically. The post processing functions will be applied bottom-up: the last post-processing function will be applied to the result of ⎕R or ⎕S, and then the second-to-last will be applied to the result of that, etc. See [the last example](#build-me-a-city-quads-with-1-flag) for an example use of a post-processing function. Code lines dedicated to post-processing functions are not counted when determining whether there are an odd or even number of lines. 35 | 36 | ### Input 37 | This is the input document – the data which is to be modified. Leave this blank for programs that produce output without input. 38 | 39 | ### Arguments 40 | Options for ⎕R and ⎕S, using `⍠` (see [documentation for Variant](http://help.dyalog.com/16.0/Content/Language/Primitive%20Operators/Variant.htm)), but in a shortened form only. The short forms correspond to the following full forms when using ⎕R and ⎕S in Dyalog APL: 41 | 42 | | Short | Full syntax | 43 | | :---: | ------------ | 44 | | `g` | `'Greedy' 0` | 45 | | `i` | `'IC' 1` | 46 | | `d` | `'Mode' 'D'` | 47 | | `m` | `'Mode' 'M'` | 48 | | `a` | `'DotAll' 1` | 49 | | `u` | `'UCP' 1` | 50 | | `o` | `'OM' 1` | 51 | 52 | See [the Options documentation](http://help.dyalog.com/16.0/Content/Language/System%20Functions/r.htm#kanchor706) for details. 53 | 54 | The entire search/replace call can optionally be repeated *N* times by adding a numeric argument, or until no further transformations can be done by adding the argument `≡`. This is equivalent to appending `⍣N` or `⍣≡` in Dyalog APL. See [documentation for the Power Operator](http://help.dyalog.com/16.0/Content/Language/Primitive%20Operators/Power%20Operator.htm) for details and [the last example](#build-me-a-city-quads-with-1-flag) for an example. 55 | 56 | `?` is a special argument which in addition to running the program, will output a proper APL function equivalent (including Arguments and post-processing functions, if applicable) to the Debug field. Use this tool to learn the proper syntax of ⎕R and ⎕S. 57 | 58 | ### Output 59 | 60 | The result of the transformed input for QuadR, and a formatted list for QuadS. If `≡` or any number is specified as argument, QuadS will merge the list items together, padding with [fill elements](http://help.dyalog.com/16.0/Content/Language/Introduction/Variables/Prototypes%20and%20Fill%20Items.htm) if necessary, before passing the result to any post-processing functions. 61 | 62 | ### Debug 63 | 64 | Error messages and the APL expression equivalents will be place here. Expand the section to see them. 65 | 66 | ## Examples 67 | 68 | ### Hello, World! 69 | ``` 70 | Hello, World! 71 | ``` 72 | As a single non-function line this replaces all occurences of `''` with `'Hello, World!'`. PCRE will find one such match and, in the case of QuadR, make the replacement, and in the case of QuadS, return the string for that one match. [Try it online!](https://tio.run/##KyxNTCn6/98jNScnX0chPL8oJ0Xx/38A "QuadR – Try It Online") 73 | 74 | ### Summation 75 | ``` 76 | .+ 77 | +/⍎⍵M 78 | ``` 79 | This will sum the numbers on each line of the Input and return one sum on each line. The first line matches the entire input line and the second line specifies a transformation function which takes the matched text (`⍵M`), executes it (`⍎`) to convert it to numbers, and sums it `+/`. [Try it online!](https://tio.run/##KyxNTCn6/19Pm0tb/1Fv36Perb7//xsrGCqYcBkpmANpCwA "QuadR – Try It Online") 80 | 81 | ### Primality checker 82 | ``` 83 | 1+ 84 | ~⍵L∊1,,∘.×⍨1↓⍳⍵L 85 | ``` 86 | Each line of the Input is an integer in unary (using `1`s). For each such number, it takes the length (`⍵L`), generates the integers from 1 to that (`⍳`), drops the first number (`1↓`), creates a multiplication table (`∘.×⍨`), flattens it (`,`), prepends one (`1,`), asks whether the match length (`⍵L`) is a member of that (`∊`), and finally negates the result. [Try it online!](https://tio.run/##KyxNTCn6/99Qm6vuUe9Wn0cdXYY6Oo86Zugdnv6od4Xho7bJj3o3g2SAahQMQQiMDblABIQJp@C0IQA "QuadR – Try It Online") 87 | 88 | ### Given a string of `[a-zA-Z ]` reverse every word (QuadR only) 89 | ``` 90 | \w+ 91 | ⌽⍵M 92 | ``` 93 | The first line matches every run of word characters, while the second line reverses (`⌽`) the match (`⍵M`). [Try it online!](https://tio.run/##KyxNTCn6/z@mXJvrUc/eR71bff//D8lIVUjLLCouUcjJzEtVyE0sSc5ILVZILUstqlQoKs1TyE9TKM8vSlFIzkgsSkwuSS3SUSjPyMxJVSgB6ixOTc7PS4FoLQLpKQbq1QAargmWBpsG5ANt0tQDAA "QuadR – Try It Online") 94 | 95 | ### Transform into upper/lower case (QuadR) 96 | ``` 97 | (.)(.) 98 | . 99 | \u1\l2 100 | \u& 101 | ``` 102 | The first line matches all runs of two characters and the third line converts the first to uppercase and the second to lowercase. The second line matches any leftover trailing character and the fourth line converts it to uppercase. [Try it online!](https://tio.run/##XY7BCsIwDIbve4qcRC8FfZYddwltagu1mWnq8OlrdbAxIRDIl//ne1Z00trZXPoMZpjqdUq3vk6tjYHARykKKWaCB6oNVABTAqm5AHvQhcEGFLRK0lF2oD2lIYpbU5bzi0TL7762KUOdZxKLhbZIof7pvizxsjIzjDs4KuQ3JPLKvRpUMHZ630W2Us9VNPyJxKOB@QA "QuadR – Try It Online") 103 | 104 | ### [What my dog really hears](https://codegolf.stackexchange.com/q/119718/43319) (QuadR) 105 | ``` 106 | rex 107 | \w 108 | & 109 | * 110 | ``` 111 | The first line matches all cases of REX (with the `i` option) and the second line all other word characters. The third line replaces all occurrences of REX with themselves and the fourth line replaces all other word characters with stars. [Try it online!](https://tio.run/##HY6xDsIwEEP3fIXbASSE8h8MLIgFieXUROUgzYnkAs3Xh5TF0rNly@9CLrWW/GruX7Mzh9Yufj3iBJXgUKUginaAE@iD84CblH3yWOjFccbiQXFOFb02mC4I/PEZHDcnUHTWXAUThYD/8rNkRaaKseNozbn2UMEZs1fdJilK/8OTbfwD "QuadR – Try It Online") 112 | 113 | ### [Build me a city](https://codegolf.stackexchange.com/q/128611/43319) (QuadS with `1` flag) 114 | 115 | ``` 116 | ⊖⍵ 117 | (.)\1* 118 | 2/⍪⍵M 119 | ``` 120 | The first line sets up a post post-processor that will flip (`⊖`) the result (`⍵`) upside down. The second line finds runs of identical characters. The third line duplicates (`2/`) the columnified (`⍪`) match (`⍵M`). The `1` flag causes the results to be merged together. [Try it online!](https://tio.run/##KyxNTCn@//9R17RHvVu5NPQ0Ywy1uIz0H/WuAvJ9//9PTExMAoHk5MKiouLi4hIICAgo/28IAA "QuadS – Try It Online") 121 | -------------------------------------------------------------------------------- /Run.dyalog: -------------------------------------------------------------------------------- 1 | ∇ output←regexes(op Run args)input;from;to;options;lines;Expand;repeat;s;r;last;fns;q;hasrepeat;postproc;combine;Quote;Nest;a;n 2 | output←⍬⊤⍬ ⍝ default result is empty matrix 3 | 4 | n←⎕UCS 10 ⍝ newline 5 | a←⎕UCS 39 ⍝ apostrofe 6 | ⍎'Nest←{⊂⍣(1=≡,⍵)⊢⍵}' 7 | ⍎'Quote←{a,a,⍨⍵/⍨1+⍵=a}' 8 | 9 | :Trap 11 22 ⍝ accept filename or actual input 10 | input←input ⎕NTIE 0 11 | :EndTrap 12 | 13 | :Trap 11 22 ⍝ accept filename or actual regex 14 | regexes←⊃⎕NGET regexes 1 15 | :EndTrap 16 | ⍎'regexes←{,¨⍣(¯2=≡⍵)⊢⍵}Nest regexes' 17 | 18 | repeat←⍎{×≢⍵:⍵ ⋄ '1'}args∩'≡',⎕D ⍝ extract repetition, if any, else 1 19 | hasrepeat←∨/args∊⍨'≡',⎕D 20 | ⍝ select options: 21 | options←('ResultText' 'Simple')('Greedy' 0)('IC' 1)('Mode' 'D')('Mode' 'M')('DotAll' 1)('UCP' 1)('OM' 1)/⍨1,'gidmauo'∊819⌶args~' -' 22 | s r←(∨/∊∘op)¨'Ss' 'Rr' 23 | :If s∨r 24 | options↓⍨←s ⍝ ResultText is not for ⎕S 25 | 26 | fns←+/∧\'⍵'∊¨regexes 27 | postproc←∊'⊢','∘{'∘,¨,∘'}'¨fns↑regexes ⍝ post-processing functions 28 | regexes↓⍨←fns 29 | 30 | last←⊃regexes↓⍨¯1+≢regexes 31 | :If '⍵'∊last ⍝ transformation function → many-to-function 32 | :OrIf 2|≢regexes ⍝ odd number of strings → many-to-one 33 | from←¯1↓regexes ⍝ remove transformation pattern/function 34 | :If ~'⍵'∊last ⍝ no ⍵ → pattern 35 | Expand←'⍵B' '⍵b' '⍵P' '⍵p' '⍵M' '⍵O' '⍵L' '⍵N'⎕R'⍵.Block' '⍵.BlockNum' '⍵.Pattern' '⍵.PatternNum' '⍵.Match' '⍵.Offsets' '⍵.Lengths' '⍵.Names' 36 | :OrIf ~≡⎕FX,⊂'to←{',(r/',⍕{'),(Expand last),(r/'}⍵'),'}' ⍝ if definition fails, revert to pattern (allows ⍵ in pattern) 37 | to←last 38 | :EndIf 39 | :Else 40 | lines←2÷⍨≢regexes 41 | from←regexes↓⍨-lines 42 | to←lines↓regexes 43 | :EndIf 44 | 45 | combine←'{⊃,/⍵↑¨⍨⌈/≢¨⍵}' 46 | q←⎕NS ⍬ 47 | q.from←⍕Quote¨Nest from 48 | :If 0=≢q.from 49 | q.from←a a 50 | :EndIf 51 | :If 1∧.=≢¨from 52 | q.(from←'(,¨',from,')') 53 | :EndIf 54 | :If 3=⎕NC'to' 55 | q.to←1⌽' ',3↓∊⎕NR'to' 56 | :Else 57 | q.to←⍕Quote¨Nest to 58 | :If 0=≢q.to 59 | q.to←a a 60 | :EndIf 61 | :If 1∧.=≢¨to 62 | q.(to←'(,¨',to,')') 63 | :EndIf 64 | :EndIf 65 | :If 3=⎕NC'repeat' 66 | q.repeat←'⍣',∊⎕NR'repeat' 67 | :ElseIf 1≢repeat 68 | q.repeat←'⍣',⍕repeat 69 | :Else 70 | q.repeat←'' 71 | :EndIf 72 | :If ×≢options 73 | q.options←'⍠',∊{' (',(Quote⊃⍵),' ',({0 1∊⍨⊂⍵:⍕⍵ ⋄ Quote ⍵}⊃⌽⍵),')'}¨options 74 | :Else 75 | q.options←'' 76 | :EndIf 77 | q.op←s r/'SR' 78 | q.postproc←2↓postproc 79 | q.postproc,←(hasrepeat∧s)/(''≡q.postproc)↓'∘',combine 80 | q.(expr←postproc,from,'⎕',op,to,options,repeat) 81 | :If '?'∊args 82 | ⍞←q.expr,n 83 | :EndIf 84 | 85 | :If 0=≢from 86 | from←'' 87 | :EndIf 88 | :If 2=⎕NC'to' 89 | :AndIf 0=≢to 90 | to←'' 91 | :EndIf 92 | 93 | :Trap 11 94 | :If r 95 | output←from ⎕R to⍠options⍣repeat⊢input 96 | :ElseIf s 97 | output←from ⎕S to⍠options⍣repeat⊢input 98 | output←(⍎combine)⍣hasrepeat⊢output ⍝ merge search results if we need to continue 99 | :EndIf 100 | output←(⍎postproc)output 101 | :Case 11 ⍝ faulty regex 102 | ⍞←'*** ',⎕DMX.(Message,(''≡Message)/⊃DM),' ***',n 103 | ⍞←'Attempted APL expression: ',q.expr,n 104 | :EndTrap 105 | :Else 106 | ⍞←'*** Left operand must be ''R'' or ''S'' ***' 107 | :EndIf 108 | ∇ 109 | -------------------------------------------------------------------------------- /quadrs: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | export DYALOG=$1 4 | export MAXWS=128M WSPATH=$DYALOG/ws 5 | 6 | cp $2 .coden.tio && echo "" >> .coden.tio 7 | 8 | cat <<- . | "$DYALOG/dyalog" -script 9 | ⎕PW←9999 10 | {}2⎕FIX'file://$(dirname "$BASH_SOURCE")/Run.dyalog' 11 | '.coden.tio'('$4'Run '${@:5}')'$3' 12 | . 13 | --------------------------------------------------------------------------------