How to Write Multiline String With Significant Whitespace at the End - swift4

I’m converting a previously concatenated string to the new multi-line string syntax introduced in Swift 4. It contains signifiant whitespace at the end of lines, so I’m using the string newline escaping to explicitly terminate the line with \n\ after the significant whitespace, to protect it from the editor (Xcode) that strips the whitespace from the end of the line.
let asciiArt = """
\ / \n\
V \
"""
Problem is with the last line, where I don’t want the newline to be part of the string, but cannot use just a single \ because it gives me error:
Escaped newline at the last line is not allowed
How do I write multiline string with significant trailing whitespace that doesn’t contain newline at the end?

Turns out the error is due to quirks in Swift parsing grammar and the workaround in Swift 4.0 and 4.1 is to insert extra newline at the end, to make the compiler happy:
let asciiArt = """
\ / \n\
V \
"""
Notice the empty line before the closing """!
In Summary: to write a multiline string that ends with significant whitespace and doesn’t contain a trailing newline, insert one more newline at the end. The compiler removes the newlines after the opening """, before the closing """ and after every line-trailing \, which leaves you with:
a string that ends in whitespace without \n,
a content compiler and
a question why people follow made-up rules ad-absurdum like robots... 🤖🤦‍♂️🤷‍♂️

Related

Alphanumeric substitution with vim

I'm using the vscode vimplugin. I have a bunch of lines that look like:
Terry,169,80,,,47,,,22,,,6,,
I want to remove all the alphanumeric characters after the first comma so I get:
Terry,,,,,,,,,,,,,
In command mode I tried:
s/^.+\,[a-zA-Z0-9-]\+//g
But this does not appear to do anything. How can I get this working?
edit:
s/^[^,]\+,[a-zA-Z0-9-]\+//g
\+ is greedy; ^.\+, eats the entire line up to the last ,.
Instead of the dot (which means "any character") use [^,] which means "any but a comma". Then ^[^,]\+, means "any characters up to the first comma".
The problem with your requirement is that you want to anchor at the beginning using ^ so you cannot use flag g — with the anchor any substitution will be done once. The only way I can solve the puzzle is to use expressions: match and preserve the anchored text and then use function substitute() with flag g.
I managed with the following expression:
:s/\(^[^,]\+\)\(,\+\)\(.\+\)$/\=submatch(1) . submatch(2) . substitute(submatch(3), '[^,]', '', 'g')/
Let me split it in parts. Searching:
\(^[^,]\+\) — first, match any non-commas
\(,\+\) — any number of commas
\(.\+\)$ — all chars to the end of the string
Substituting:
\= — the substitution is an expression
See http://vimdoc.sourceforge.net/htmldoc/change.html#sub-replace-expression
submatch(1) — replace with the first match (non-commas anchored with ^)
submatch(2) — replace with the second match (commas)
substitute(submatch(3), '[^,]', '', 'g') — replace in the rest of the string
The last call to substitute() is simple, it replaces all non-commas with empty strings.
PS. Tested in real vim, not vscode.

confused about what must be escaped for sed

I want to replace specific strings in php files automatically using sed. Some work, and some do not. I already investigated this is not an issue with the replacement string but with the string that is to be replaced. I already tried to escape [ and ] with no success. It seems to be the whitespace within the () - not whitespaces in general. The first whitespaces (around the = ) do not have any problems. Please can someone point me to the problem:
sed -e "1,\$s/$adm = substr($path . rawurlencode($upload['name']) , 16);/$adm = rawurlencode($upload['name']); # fix 23/g" -i administration/identify.php
I already tried to shorten the string which should be replaced and the result was if I cut it directly behind $path it works, with the following whitespace it does not. Escaping whitespace has no effect...
what must be escaped for sed
The following characters have special meaning in sed and have to be escaped with \ for the regex to be taken literally:
\
[
the character used in separating s command parts, ie. / here
.
*
& only replacement string
Newline character is handled specially as the end of the string, but can be replaced for \n.
So first escape all special characters in input and then pass it to sed:
rgx="$adm = substr($path . rawurlencode($upload['name']) , 16);"
rgx_escaped=$(sed 's/[\\\[\.\*\/&]/\\&/g' <<<"$rgx")
sed "s/$rgx_escaped/ etc."
See Escape a string for a sed replace pattern for a generic escaping solution.
You may use
sed -i 's/\$adm = substr(\$path \. rawurlencode(\$upload\['"'"'name'"'"']) , 16);/$adm = rawurlencode($upload['"'"'name'"'"']); # fix 23/g' administration/identify.php
Note:
the sed command is basically wrapped in single quotes, the variable expansion won't occur inside single quotes
In the POSIX BRE syntax, ( matches a literal (, you do not need to escape ) either, but you need to escape [ and . that must match themselves
The single quotes require additional quoting with concatenation.

swift - replacing characters from keyboard [duplicate]

I have tried to print it but it just by passes because it's an escaped character.
e.g output should be as follows.
\correct
For that and also future reference:
\0 – Null character (that is a zero after the slash)
\\ – Backslash itself. Since the backslash is used to escape other characters, it needs a special escape to actually print itself.
\t – Horizontal tab
\n – Line Feed
\r – Carriage Return
\” – Double quote. Since the quotes denote a String literal, this is necessary if you actually want to print one.
\’ – Single Quote. Similar reason to above.
Use the following code for Swift 5, Xcode 10.2
let myText = #"This is a Backslash: \"#
print(myText)
Output:
This is a Backslash: \
Now not required to add a double slash to use a single slash in swift 5, even now required slash before some character, for example, single quote, double quote etc.
See this post for latest update about swift 5
https://www.hackingwithswift.com/articles/126/whats-new-in-swift-5-0
var s1: String = "I love my "
let s2: String = "country"
s1 += "\"\(s2)\""
print(s1)
It will print I love my "country"
The backslash character \ acts as an escape character when used in a string. This means you can use, for example, double quotes, in a string by pre-pending them with \. The same also applies for the backslash character itself, which is to say that println("\\") will result in just \ being printed.

Fix improper quotes in text

I receive text from some writers that has a string like: string "string "string.
I want it to read string "string" string.
I've tried various sed tricks but none work.
Here is one failed attempt:
sed 's/.* "/.*"/g'
Your attempt fails for multiple reasons.
The wildcard .* will consume as much as it can in the string, meaning it will only ever allow a single substitution to happen (the final double quote in the string).
You cannot use .* in the substitution part -- what you substitute with is just a string, not a regular expression. The way to handle "whatever (part of) the regex matched" is through backreferences.
So here is a slightly less broken attempt:
sed 's/"\([^"]*\) "/"\1"/g' file
This will find a double quote, then find and capture anything which is not a double quote, then find a space and a double quote; and substitute the entire match with a double quote, the first captured expression (aka back reference, or backref), and another double quote. This should fix strings where the only problem is a number of spaces inside the closing double quotes, but not missing whitespace after the closing double quote, nor strings with leading spaces inside the double quotes or unpaired double quotes.
The lack of spaces after can easily be added;
sed 's/"\([^"]*\) " */"\1" /g;s/ $//' file
This will add a space after every closing double quote, and finally trim any space at end of line to fix up this corner case.
Now, you could either try to update the regex for leading spaces, or just do another pass with a similar regex for those. I would go with the latter approach, even though the former is feasible as well (but will require a much more complex regex, and the corner cases are harder to keep in your head).
sed 's/"\([^"]*\) " */"\1" /g;s/ $//;
s/ *" \([^"]*\)"/ "\1"/g;s/^ //' file
This will still fail for inputs with unbalanced double quotes, which are darn near impossible to handle completely automatically anyway (how do you postulate where to add a missing double quote?)
This may work for some cases but may fail with unbalanced quotes:
sed 's/"\([^"]*\S\)\s\s*"/"\1"/g'
to also add space after a quoted phrase, if a space is missing:
sed -e 's/"\([^"]*\S\)\s\s*"/"\1"/g' -e 's/\("[^"]*"\)\([^"]\)/\1 \2/g'
Here is an awk solution:
echo 'string "string "string.' | awk -F' "' '{for (i=1;i<=NF;i++) printf (i%2==0?"\"":"")"%s"(i%2==0?"\"":"")(i!=NF?" ":""),$i;print ""}'
string "string" string.
It looks at numbers of quotes, and every second quotes should be behind text.

meaning of the following regular expressions written in perl

Here is a piece of code
while($l=~/(\\\s*)$/) {
statements;
}
$l contains a line of text taken form file, in effect this code is for go through lines in file.
Questions:
I don't clearly understand what the condition in while is doing. I think it is trying to match group of \ followed by some number of white spaces at the end of line and loop should stop whenever a line ends with \ and may be some white spaces. I am not sure of it.
I came across statement $a ~= s/^(.*$)/$1/ . What I understand that ^ will force matching at the beginning of string, but in (.*$) would mean match all the characters at the end of string . Dose it mean that the statement is trying to find if any group of character at the end is same as group of character in the beginning of text ?
It is interesting to note that this statement:
while ( $l =~ /(\\\s*)$/ ) {
Is an infinite loop unless $l is altered inside the loop so that the regex no longer matches. As has already been mentioned by others, this is what it matches:
( ... ) a capture group, captures string to $1 (that's the number one, not lower case L)
\\ matches a literal backslash
\s* matches 0 or more whitespace characters.
$ matches end of line with optional newline.
Since you do not have the /g modifier, this regex will not iterate through matches, it will simply check if there is a match, resetting the regex each iteration, thereby causing an endless loop.
The statement
$a ~= s/^(.*$)/$1/
Looks rather pointless. It captures a string of characters up until end of string, then replaces it with itself. The captured text is stored in $1 and is simply replaced. The only marginally useful thing about this regex is that:
It matches up until newline \n, and nothing further, which may be of some use to a parser. A period . matches any character except newline, unless the /s modifier is present on the regex.
It captures the line in $1 for future use. However, a simple /^(.*$)/ would do the same.
1. the while
Usually while (regex) is used with the /g modifier, otherwise, if it matches, you get an infinite loop (unless you exit the loop, like using last).
statements would be executed continuously in an infinite loop.
In your case, adding the g
while($l=~/(\\\s*)$/g)
will have the while make only one loop, due to the $ - making a match unique (whatever matches up to the end of string is unique, as $ marks the end, and there is nothing after...).
2. $a ~= s/^(.*$)/$1/
This is a substitution. If the string ^.*$ matches (and it will, since ^.*$ matches (almost, see comment) anything) it is replaced with... $1 or what's inside the (), ie itself, since the match occurs from 1st char to the end of string
^ means beginning of string
(.*) means all chars
$ end of string
so that will replace $a with itself - probably not what you want.
it matches a literal backslash followed by 0 or more spaces followed by the end of the line.
it executes statements for all the lines in that text file that contain a \, followed by zero or more spaces ( \s* ), at the end of the line ($).
It matches lines that end with a backslash character, ignoring any trailing whitespace characters.
Ending a line with a backslash is used in some languages and data files to indicate that the line is being continued on the next line. So I suspect this is part of a parser that merges these continuation lines.
If you enter a regular expression at RegExr and hover your mouse over the pieces, it displays the meaning of each piece in a tooltip.
(\\\s*)$ this regex means --- a \ followed by zero or more number of white space characters which is followed by end of the line. Since you have your regex in (...), you can extract what you matched using $1, if you need.
http://rubular.com/r/dtHtEPh5DX
EDIT -- based on your update
$a ~= s/^(.$)/$1/ --- this is search and replace. So your regex matches a line which contains exactly one character (since you use . http://www.regular-expressions.info/dot.html), except a new-line character. Since you use (...), the character which matched the regex is extracted and stored in variable a
EDIT -- you changed your regex so here is the updated answer
$a ~= s/^(.*$)/$1/ -- same as above except now it matches zero or more characters (except new-line)