Ruby rspec check string begins with certain values - ruby

I have a string that begins with a set start and then is filled to 252 characters by randomly generated letters. (237 random chars - so that the end length is 252 characters)
For the purpose of testing the string starts off with TESTDATAMENDNOW and the rest is random capital letters.
How can I test that the characters are all capital letters
and that the string begins with TESTDATAMENDNOW
I have tried to use regex expressions to define this but I'm not too sure how to get them to work properly, and what I have tried so far seems not to be working.
EDIT: Clarity

expect(string).to match(/\ATESTDATAMENDNOW[A-Z]{237}\z/)
237 because 252 minus the length of "TESTDATAMENDNOW" is 237.

Here's another way that does not use a regex:
str = "TESTDATAMENDNOW"
expect(string[0,str.size]).eq(str)
expect(string.delete("ABCDEFGHIJKLMNOPQRSTUVWXYZ").eq("")
expect(string.size).eq(252)

Related

Replace the last character or number of a string | Freemarker

I need to check if the last number of character of a ${string} is equal to 9.
The string or numbers that I have to handle with is something 831, 519 or 1351.
However I dont know how do do it properly. I tried already something like:
${string?replace((string.length)-1,"9")}
At the end there should be instead of 831 --> 839 or 1351 --> 1359 and so on.
Any sugestions about how I can archive this ?
Oh and by the way. If I use the fuction above this error massage comes up:
Script error: You have used ?number on a string-value which is not a number (or is empty or contains spaces).
And what I tried also was:
code snippet
Because the original number is somethink like 831.896.
You could use string slicing to keep all characters except for the last one like this:
<#assign string = "1234">
<#assign string = string[0..<string?length-1] + "9">
${string}
Results in:
1239
Since you want to replace that thing, use ?replace. This replaces the last character with 9, if the last character is a digit that's not already 9:
${s?replace("[0-8]$", '9', 'r')}

Characters at the end do not match

I need to match all the alphabets and numbers in a string str.
This is my code.
str.match(/^(AB)(\d+)([A-Za-z][0-9])?/)
When str = AB57933A [sic], it matches only AB57933, and not the characters appended after the numbers.
If I try with str = AB57933AbC [sic], it matches only AB57933; it only matches up to the last number, and not the characters after that.
In the way you have written it:
/^(AB)(\d+)([A-Za-z][0-9])/
you impose that the last character is between 0 and 9, you can replace it depending on your needs by if you do not expect digits after the last letter
/^(AB)(\d+)([A-Za-z]+)/
or by
/^(AB)(\d+)([A-Za-z0-9]+)/
if AB57933AbC12 are also accepted as valid input.
Last but not least, if you do not use back references you can omit the parenthesis as you do not need capturing groups

Regex for series of four digits each up to 100

I'm trying to write a regex to validate a string and accepts only a series of four comma-separated digits, each up to 100. Something like this would be valid:
20,30,40,50
and these invalid:
120,0,20,0
20,30,40,ss
invalid_string
Any thoughts?
They're used for CMYK colours. We just need to store them here, not use them.
Number Range and Subroutine
In Ruby 2+, for a compact regex, use this:
^([0-9]|[1-9][0-9]|100)(?:,\g<1>){3}$
Explanation
The ^ anchor asserts that we are at the beginning of the string
The parentheses around ([0-9]|[1-9][0-9]|100) match a number from 0 to 100 and define subroutine #1
(?:,\g<1>) matches one comma and the expression defined by subroutine # 1
The {3} quantifier repeats that three times
The $ anchor asserts that we are at the end of the string
I'd save myself the headache of using regex for a number related problem. Also the validation message will look akward so it's better to make your own:
validate :that_string_has_only_4_numbers_upto_100
def that_string_has_only_4_numbers_upto_100
errors.add(:str, 'is not valid.') unless str.split(/,/).all? { |n| 1..100 === n.to_i }
end
Unless you a re regex jedi guru like #zx81 :p.
^(?:\d{1,2},){3}\d{1,2}$
Try this

How do I match repeated characters?

How do I find repeated characters using a regular expression?
If I have aaabbab, I would like to match only characters which have three repetitions:
aaa
Try string.scan(/((.)\2{2,})/).map(&:first), where string is your string of characters.
The way this works is that it looks for any character and captures it (the dot), then matches repeats of that character (the \2 backreference) 2 or more times (the {2,} range means "anywhere between 2 and infinity times"). Scan will return an array of arrays, so we map the first matches out of it to get the desired results.

Code golf: find all anagrams

A word is an anagram if the letters in that word can be re-arranged to form a different word.
Task:
The shortest source code by character count to find all sets of anagrams given a word list.
Spaces and new lines should be counted as characters
Use the code ruler
---------10--------20--------30--------40--------50--------60--------70--------80--------90--------100-------110-------120
Input:
a list of words from stdin with each word separated by a new line.
e.g.
A
A's
AOL
AOL's
Aachen
Aachen's
Aaliyah
Aaliyah's
Aaron
Aaron's
Abbas
Abbasid
Abbasid's
Output:
All sets of anagrams, with each set separated by a separate line.
Example run:
./anagram < words
marcos caroms macros
lump's plum's
dewar's wader's
postman tampons
dent tend
macho mocha
stoker's stroke's
hops posh shop
chasity scythia
...
I have a 149 char perl solution which I'll post as soon as a few more people post :)
Have fun!
EDIT: Clarifications
Assume anagrams are case insensitive (i.e. upper and lower case letters are equivalent)
Only sets with more than 1 item should be printed
Each set of anagrams should only be printed once
Each word in an anagram set should only occur once
EDIT2: More Clarifications
If two words differ only in capitalization, they should be collapsed into the same word, and it's up to you to decide which capitalization scheme to use for the collapsed word
sets of words only have to end in a new line, as long as each word is separated in some way, e.g. comma separated, or space separated is valid. I understand some languages have quick array printing methods built in so this should allow you to take advantage of that if it doesn't output space separated arrays.
Powershell, 104 97 91 86 83 chars
$k=#{};$input|%{$k["$([char[]]$_|%{$_+0}|sort)"]+=#($_)}
$k.Values|?{$_[1]}|%{"$_"}
Update for the new requirement (+8 chars):
To exclude the words that only differ in capitalization, we could just remove the duplicates (case-insensitvely) from the input list, i.e. $input|sort -u where -u stands for -unique. sort is case-insenstive by default:
$k=#{};$input|sort -u|%{$k["$([char[]]$_|%{$_+0}|sort)"]+=#($_)}
$k.Values|?{$_[1]}|%{"$_"}
Explanation of the [char[]]$_|%{$_+0}|sort -part
It's a key for the hashtable entry under which anagrams of a word are stored. My initial solution was: $_.ToLower().ToCharArray()|sort. Then I discovered I didn't need ToLower() for the key, as hashtable lookups are case-insensitive.
[char[]]$_|sort would be ideal, but sorting of the chars for the key needs to be case-insensitive (otherwise Cab and abc would be stored under different keys). Unfortunately, sort is not case-insenstive for chars (only for strings).
What we need is [string[]][char[]]$_|sort, but I found a shorter way of converting each char to string, which is to concat something else to it, in this case an integer 0, hence [char[]]$_|%{$_+0}|sort. This doesn't affect the sorting order, and the actual key ends up being something like: d0 o0 r0 w0. It's not pretty, but it does the job :)
Perl, 59 characters
chop,$_{join'',sort split//,lc}.="$_ "for<>;/ ./&&say for%_
Note that this requires Perl 5.10 (for the say function).
Haskell, 147 chars
prior sizes: 150 159 chars
import Char
import List
x=sort.map toLower
g&a=g(x a).x
main=interact$unlines.map unwords.filter((>1).length).groupBy((==)&).sortBy(compare&).lines
This version, at 165 chars satisifies the new, clarified rules:
import Char
import List
y=map toLower
x=sort.y
g&f=(.f).g.f
w[_]="";w a=show a++"\n"
main=interact$concatMap(w.nubBy((==)&y)).groupBy((==)&x).sortBy(compare&x).lines
This version handles:
Words in the input that differ only by case should only count as one word
The output needs to be one anagram set per line, but extra punctuation is acceptable
Ruby, 94 characters
h={};(h[$_.upcase.bytes.sort]||=[])<<$_ while gets&&chomp;h.each{|k,v|puts v.join' 'if v.at 1}
Python, 167 characters, includes I/O
import sys
d={}
for l in sys.stdin.readlines():
l=l[:-1]
k=''.join(sorted(l)).lower()
d[k]=d.pop(k,[])+[l]
for k in d:
if len(d[k])>1: print(' '.join(d[k]))
Without the input code (i.e. if we assume the wordlist already in a list w), it's only 134 characters:
d={}
for l in w:
l=l[:-1]
k=''.join(lower(sorted(l)))
d[k]=d.pop(k,[])+[l]
for k in d:
if len(d[k])>1: print(' '.join(d[k]))
AWK - 119
{split(toupper($1),a,"");asort(a);s="";for(i=1;a[i];)s=a[i++]s;x[s]=x[s]$1" "}
END{for(i in x)if(x[i]~/ .* /)print x[i]}
AWK does not have a join function like Python, or it could have been shorter...
It assumes uppercase and lowercase as different.
C++, 542 chars
#include <iostream>
#include <map>
#include <vector>
#include <boost/algorithm/string.hpp>
#define ci const_iterator
int main(){using namespace std;typedef string s;typedef vector<s> vs;vs l;
copy(istream_iterator<s>(cin),istream_iterator<s>(),back_inserter(l));map<s, vs> r;
for (vs::ci i=l.begin(),e=l.end();i!=e;++i){s a=boost::to_lower_copy(*i);
sort(a.begin(),a.end());r[a].push_back(*i);}for (map<s,vs>::ci i=r.begin(),e=r.end();
i!=e;++i)if(i->second.size()>1)*copy(i->second.begin(),i->second.end(),
ostream_iterator<s>(cout," "))="\n";}
Python, O(n^2)
import sys;
words=sys.stdin.readlines()
def s(x):return sorted(x.lower());
print '\n'.join([''.join([a.replace('\n',' ') for a in words if(s(a)==s(w))]) for w in words])

Resources