MySQL space comparsion hell - mysql

Why this query:
SELECT
"hello" = " hello",
"hello" = "hello ",
"hello" <> "hello ",
"hello" LIKE "hello ",
"hello" LIKE "hello%"
returns me these results:
"hello" = " hello" -> 0
"hello" = "hello " -> 1
"hello" <> "hello " -> 0
"hello" LIKE "hello " -> 0
"hello" LIKE "hello%" -> 1
In particular, I was expecting "hello" = "hello " to be false and "hello" <> "hello " to be true (the LIKE in this case, behaves exactly as I wanted).
Why MySQL compares spaces in such an arbitrary and inconsistent way ? (such as returning 0 on "hello" = " hello" AND 1 on "hello" = "hello ").
Is there any way to configure MySQL to work ALWAYS in "strict mode" (in other words, to make it always behave like LIKE for the varchar/text comparsion) ?
Sadly i'm using a proprietary framework and I cannot force it to always use the LIKE in queries for text comparsions or trimming all the inputs.

"hello" = " hello" -- 0,
Because it is not an exact match
"hello" = "hello " -- 1,
Because trailing spaces are ignored for varchar types
"hello" <> "hello " -- 0,
Because trailing spaces are ignored for varchar types
"hello" LIKE "hello " -- 0,
Because trailing spaces are ignored for varchar types and LIKE performs matching on a per-char basis
"hello" LIKE "hello%" -- 1,
Because it is a partial pattern matching
If you want strict checking, you can use binary on values to be compared.
mysql> select binary('hello')=binary('hello ') bin_eq, 'hello'='hello ' eq;
+--------+----+
| bin_eq | eq |
+--------+----+
| 0 | 1 |
+--------+----+
Refer to:
MySQL: Comparison Functions and Operators

The trailing spaces are omitted if the column is of type char or varchar. See the discussion in the documentation.

All MySQL collations are of type PADSPACE. This means that all CHAR, VARCHAR, and TEXT values in MySQL are compared without regard to any trailing spaces. “Comparison” in this context does not include the LIKE pattern-matching operator, for which trailing spaces are significant.

Related

Can a string without white space be considered a valid JSON?

I'm using JsonParser.parseString which is passing if i give a value like "1234" or "abcd" (ignore case). Can anyone explain this?
Your first example is valid JSON for a number. Using JavaScript's parser:
console.log(JSON.parse('1234'));
It seems unlikely to me that a JSON parser was happy with your second example, because it's not valid:
console.log(JSON.parse('abcd'));
...unless it actually had quotes around it, in which case it's valid JSON for a string:
console.log(JSON.parse('"abcd"'));
But even objects don't have to have whitespace, for instance:
console.log(JSON.parse('{"example":"object"}'));
I'm using JsonParser.parseString which is passing if i give a value like "1234" or "abcd" (ignore case). Can anyone explain this?
The current specification for application/json is RFC 8259
Highlights from the production rules:
JSON-text = ws value ws
value = false / null / true / object / array / number / string
number = [ minus ] int [ frac ] [ exp ]
int = zero / ( digit1-9 *DIGIT )
string = quotation-mark *char quotation-mark
quotation-mark = %x22 ; "
Therefore:
A sequence of digits (ex: 1234) is a valid JSON-text
A sequence of digits enclosed in double quotes (ex: "1234") is a valid JSON-text
A sequence of "unescaped" characters enclosed in double quotes (ex: "abcd") is a valid JSON-text
A sequence of "unescaped" characters without enclosing double quotes (ex: abcd) is not a valid JSON-text.
cat <<TEST | jq .
"abcd"
TEST
"abcd"
cat <<TEST | jq .
abcd
TEST
parse error: Invalid numeric literal at line 2, column 0

Strange interaction between print and the ternary conditional operator

Ran into a strange interaction between print and the ternary conditional operator that I don't understand. If we do...:
print 'foo, ' . (1 ? 'yes' : 'no') . ' bar';
...then we get the output...:
foo, yes bar
...as we would expect. However, if we do...:
print (1 ? 'yes' : 'no') . ' bar';
...then we just get the output...:
yes
Why isn't " bar" getting appended to the output in the second case?
Let's do it, but for real -- that is, with warnings on
perl -we'print (1 ? "yes" : "no") . " bar"'
It prints
print (...) interpreted as function at -e line 1.
Useless use of concatenation (.) or string in void context at -e line 1.
yes
(but no newline at the end)
So since (1 ? "yes" : "no") is taken as the argument list for the print function then the ternary is evaluated to yes and that is the argument for print and so that, alone, is printed. As this is a known "gotcha," which can easily be done in error, we are kindly given a warning for it.
Then the string " bar" is concatenated (to the return value of print which is 1), what is meaningless in void context, and for what we also get a warning.
One workaround is to prepend a +, forcing the interpretation of () as an expression
perl -we'print +(1 ? "yes" : "no") . " bar", "\n"'
Or, call the print as function properly, with full parenthesis
perl -we'print( (1 ? "yes" : "no") . " bar", "\n" )'
where I've added the newline in both cases.
See this post for a detailed discussion of a related example and precise documentation links.
If the first non-whitespace character after a function name is an opening parenthesis, then Perl will interpret that as the start of the function's parameter list and the matching closing parenthesis will be used as the end of the parameter list. This is one of the things that use warnings will tell you about.
The usual fix is to insert a + before the opening parenthesis.
$ perl -e "print (1 ? 'yes' : 'no') . ' bar'"
yes
$ perl -e "print +(1 ? 'yes' : 'no') . ' bar'"
yes bar

Multi line string trim

I have a problem string which has multiple lines:
line1
Link1: //website/go/<example>
line2
I am trying to make trim to get just web page link part (just address which can be various - in this case "//website/go/") but there are some extra signs before and after.
My try:
set temp [string map { " " "" "line1" "" "Link1: " "" "line2" "" } $output]
puts "found link : $temp
And the output of it is:
found link :<empty line>
//website/go/<example>
<empty line>`
How can I remove all white spaces, newlines, etc. and trim it in way to get just the part of the string which I am looking for. In this case to get just: //website/go/<example>?
Given this input data:
line1
Link1: //website/go/<example>
line2
You can use string map as you do and then post-process the result with string trim (assuming you only expect one thing left at the end) or remove the newlines with another mapping element. On two lines for clarity:
set temp [string map { " " "" "line1" "" "Link1: " "" "line2" "" } $output]
set temp [string trim $temp]
puts "found link : $temp
However, in this case I'd actually use regexp to pick the data I want:
regexp -line {Link1:\s+(.*\S)} $output -> temp
puts "found link : $temp
Regular expressions tend to be more suitable for parsing part-formatted data, provided you remember to keep them short. The longer a RE is, the harder it is to understand.

Parsing JSON file in powershell with specific characters

I am trying to get the values in powershell within specific characters. Basically I have a json with thousands of objects like this
"Name": "AllZones_APOPreface_GeographyMatch_FromBRE_ToSTR",
"Sequence": 0,
"Condition": "this.TripOriginLocationCode==\"BRE\"&&this.TripDestinationLocationCode==\"STR\"",
"Action": "this.FeesRate=0.19m;this.ZoneCode=\"Zone1\";halt",
"ElseAction": ""
I want everything within \" \"
IE here I would see that BRE and STR is Zone1
All I need is those 3 things outputted.
I have been searching how to do it with ConvertFrom-Json but no success, maybe I just havent found a good article on this.
Thanks
Start by representing your JSON as a string:
$myjson = #'
{
"Name": "AllZones_APOPreface_GeographyMatch_FromBRE_ToSTR",
"Sequence": 0,
"Condition": "this.TripOriginLocationCode==\"BRE\"&&this.TripDestinationLocationCode==\"STR\"",
"Action": "this.FeesRate=0.19m;this.ZoneCode=\"Zone1\";halt",
"ElseAction": ""
}
'#
Next, create a regular expression that matches everything in between \" and \", that's under 10 characters long (else it'll match unwanted results).
$regex = [regex]::new('\\"(?<content>.{1,10})\\"')
Next, perform the regular expression comparison, by calling the Matches() method on the regular expression. Pass your JSON string into the method parameters, as the text that you want to perform the comparison against.
$matchlist = $regex.Matches($myjson)
Finally, grab the content match group that was defined in the regular expression, and extract the values from it.
$matchlist.Groups.Where({ $PSItem.Name -eq 'content' }).Value
Result
BRE
STR
Zone1
Approach #2: Use Regex Look-behinds for more accurate matching
Here's a more specific regular expression that uses look-behinds to validate each field appropriately. Then we assign each match to a developer-friendly variable name.
$regex = [regex]::new('(?<=TripOriginLocationCode==\\")(?<OriginCode>\w+)|(?<=TripDestinationLocationCode==\\")(?<DestinationCode>\w+)|(?<=ZoneCode=\\")(?<ZoneCode>\w+)')
$matchlist = $regex.Matches($myjson)
### Assign each component to its own friendly variable name
$OriginCode, $DestinationCode, $ZoneCode = $matchlist[0].Value, $matchlist[1].Value, $matchlist[2].Value
### Construct a string from the individual components
'Your origin code is {0}, your destination code is {1}, and your zone code is {2}' -f $OriginCode, $DestinationCode, $ZoneCode
Result
Your origin code is BRE, your destination code is STR, and your zone code is Zone1

How to escape special characters in xpath?

I am searching for an HTML node that contains this text:
(~! # # $ % ^ & * ( ) _ + { } | : " < > ? ` - = [ ] \ ; ‘ , . / ).
But xpath is obviously having problems because it's not recognizing the above as an actual text to search for but rather as part of the xpath expression, which is why I am getting the error:
is not a valid XPath expression.
So how would I convert the above to a text or string to avoid this issue?
Thanks