Preserving whitespace / indentation in Rails database column - ruby-on-rails

I have blocks of pseudo-code text stored in a database that get printed off line-by-line and displayed in HTML.
Pseudo-code entered in text column in database:
while (counter <= 10) {
printf("Enter grade: ");
scanf("%d", &grade);
total = total + grade;
counter = counter + 1;
} /* end while */
Controller:
def index
#code = Code.first // just a filler for the time being
end
Index:
- #code.cont.each_line do |line|
- i += 1
.line
%span= i
%li.line= line
- i = 0
Somewhere along the way Ruby automatically strips out any whitespace and just leaves me with the text. I'd like to know how to preserve this so that
This:
while (counter <= 10) {
printf("Enter grade: ");
scanf("%d", &grade);
total = total + grade;
counter = counter + 1;
} /* end while */
Doesn't come out as this:
while (counter <=
printf("Enter grade: ");
scanf("%d", &grade);
total = total + grade;
counter = counter + 1;
} /* end while */

I'm pretty sure your space characters are there, but you can't see them due to the way HTML handles whitespace. Double check this by putting your text into a variable and dumping it to console with a simple puts my_chunk_of_text. If the spaces are there (and I can't see why they wouldn't be, based on the code you posted), you have a couple of alternatives:
1) Sandwich your displayed text with the <pre> tag, which renders preformatted text. You're going to want to do this in your view, like this:
<pre><%= #my_chunk_of_text %></pre>
2) Save the text in HTML format, with non-breaking spaces ( ) wherever you want a space to appear, and <br> where you need a newline. This code can be rendered in your view with the html_safe helper.
<%= #my_chunk_of_text.html_safe %>

Related

Creating Random Strinngs in Ruby with at least one sepcial character, one digit, one upper-case, one lowercase with no characters repeated in Ruby

My task is to generate a random string with following parameters:
At least one Uppercase
At least one lower
At least one digit
No repeated chars/digits allowed ( e.g. aa not allowed, aba is allowed, Aa is allowed)
I'm able to generate a random string with 1,2,3 parameters but parameter 4 logic is missing.
inputChars = [('a'..'z'), ('A'..'Z'),(0..9)].map(&:to_a).flatten
string = (0...16).map { inputChars[rand(inputChars.length)] }.join
require 'set'
inputChars = [('a'..'z'), ('A'..'Z'),(0..9)].map(&:to_a).flatten
set_string = Set.new
loop do
break if set_string.size == 16
cr = inputChars[rand(inputChars.length)]
set_string << cr
end
output = set_string.to_a.join
i just change your map operation to loop operation and add Set data structure to store the character from random inputChars operation. Using Set will not allow same character
Let's begin by defining two constants.
CHARS_BY_TYPE = {
lower: ('a'..'z').to_a.freeze,
upper: ('A'..'Z').to_a.freeze,
digit: ('0'..'9').to_a.freeze
}.freeze
ALL = (CHARS_BY_TYPE[:lower] + CHARS_BY_TYPE[:upper] + CHARS_BY_TYPE[:digit]).freeze
#=> [["a", "b",..., "z", "A", "B",..., "Z", "0", "1",..., "9"]
I will initially build a string of a specified length by randomly selecting one character at a time from the array ALL, ensuring that no two consecutive characters are the same. There is no assurance, however, that the resulting string will contain at least one uppercase letter, one lowercase letter and one digit.
def append_random_char(last_char)
loop do
ch = ALL.sample
break ch unless ch == last_char
end
end
Our main method will begin as follows:
def random_string(str_len)
raise ArgumentError if str_len < 3
(str_len - 2).times.with_object('') { |_,s| s << append_random_char(s[-1]) }
# ...
end
For example:
s = random_string(40)
#=> "arN64kDw6ClzcNMj8WAkj1NJC2B5oFoRlcXl5S"
str_len is the required string length, 40 in the example. Observe that s contains 38 characters of which no two successive characters are equal. We will need to add 2 characters later. If the string contained no digits, for example, at least one of those two characters added (at a random location) will be a (randomly-selected) digit. If the string were shorter and contained, for example, digits only, the two characters added will be an uppercase letter and a lowercase letter.
Next we need to see if the string is lacking an uppercase letter, a lowercase letter and/or a digit. (It cannot be missing all three, as the string must contain at least three characters.)
require 'set'
def types_to_add(str)
[:lower, :upper, :digit].select do |type|
st = CHARS_BY_TYPE[type].to_set
str.each_char.none? { |ch| st.include?(ch) }
end
end
For the random string generated above we obtain:
types_to_add(s)
#=> []
meaning that the string contains at least one uppercase letter, one lowercase letter and one digit. Try this:
types_to_add(s.gsub(/\d|[A-Z]/, '')
#=> [:upper, :digit]
See Enumerable#none?. CHARS_BY_TYPE[type] is converted to a set merely to speed look-ups.
Suppose now we need to insert an uppercase letter, lowercase letter or digit to satisfy the requirement that there is at least one of each in the string. Specifically, we wish to insert a randomly-drawn character (from CHARS_BY_TYPE[:lower], CHARS_BY_TYPE[:upper] or CHARS_BY_TYPE[:digit]) at a random location in the string we are constructing, with the restriction that neither the preceding nor following character is the same character.
def insert_in_string(str, ch)
i = loop do
i = rand(str.size + 1)
next if ch == str[i]
break i if i.zero? || ch != str[i-1]
end
str.insert(i, ch)
end
For example, if we were to insert the character '0' into (a copy of) our string s (which is not needed):
insert_in_string(s.dup, '0')
#=> "arN64kDw6ClzcN0Mj8WAkj1NJC2B5oFoRlcXl5S"
s #=> "arN64kDw6ClzcNMj8WAkj1NJC2B5oFoRlcXl5S"
^
This inserts the character ch before the character in str at index i. If rand(str.size + 1) returns str.size ch is inserted after the last character of str.
Following this operation the final step is to use the method append_random_char to build the string out to the desired length.
The completed main method is as follows.
def random_string(str_len)
raise ArgumentError if str_len < 3
s = (str_len - 2).times.with_object('') { |_,s| s << append_random_char(s[-1]) }
types_to_add(s).each { |type| insert_in_string(s, CHARS_BY_TYPE[type].sample) }
(str_len - s.size).times { s << append_random_char(s[-1]) }
s
end
s = random_string(40)
#=> "PtQrVFZWUYFwiwRy3ySfAy42G1NT98J6cMVMaWeT"
s.match?(/[a-z]/)
#=> true
s.match?(/[A-Z]/)
#=> true
s.match?(/\d/)
#=> true
s.size
#=> 40
This is how I would do it (warning: Not tested. Just want to present the idea
for my algorithm). I first take a random number for the length of the resulting random string (the length will be between 4 and 16 characters). Then I determine
randomly, how many of them are upper case / lower case / digits, and based on
these decision, I generate the string, ensuring that I don't get any duplicates
in succession.
uchars=('A'..'Z').to_a
lchars=('a'..'z').to_a
dchars=('0'..'9').to_a
charmap = { u: uchars, l: lchars, d: dchars }
total_length=rand(13)+4 # Total length of string to be generated
total_u=rand(total_length-3)+1 # Total number of uchars to be generated
total_l=rand(total_length-total_u-2)+1 # Total number of lchars
total_d=total_length-total_u-total_l # Total number of digits
# Array of types to generate
chartypes=([:u]*total_u + [:l]*total_l + [:d]*total_d).shuffle
# chartypes is an array similar to [:u,:d,:d,:l,:u], where the
# symbols designate the kind of character to be generated.
# outstr : random string to be generated
outstr = charmap[chartypes.first].sample
last_char = outstr.dup
total_length.times do |index|
loop do
nextchar = charmap[chartypes[index]].sample
if nextchar != last_char
outstr << nextchar
last_char = nextchar
break
end
end
end

Navigating word by word through TWebBrowser control (MSHTML)

I am trying to navigate through MSHTML (TWebBrowser) document word by word for spell checking each word. But I have problems:
1) it selects words oddly - For example "Abc: def" - the selection is "Abc" as first and ":" as second word. Also, if a word ends with space for example "Abc def" it would select "Abc " with the trailing space included. Is there a way to select only what is the word and not the trailing spaces or non-word characters? Or is this the best move can offer and it is up to programmer to filter the words correctly?
2) Is there a way to specify which delimiters it will use for example only to let it use space as a delimiter and not colons, dashes or other characters? (Microsoft docs say - "Word - Moves one or more words. A word is a collection of characters terminated by a space or other white space character. ", but it also uses other delimiters, not just space, tabs and similar)
Current code is:
bool SelectNext(bool firstonly = false)
{
DelphiInterface<IHTMLDocument2> diDoc = WB->Document;
if (diDoc)
{
DelphiInterface<IHTMLSelectionObject> diSel = diDoc->selection;
if (diSel)
{
if (firstonly) diSel->empty();
if (diSel->type_ == "None" || diSel->type_ == "Text")
{
DelphiInterface<IDispatch> diRangeDisp;
if (SUCCEEDED(diSel->createRange(diRangeDisp)) && diRangeDisp)
{
DelphiInterface<IHTMLTxtRange> diRange;
if (SUCCEEDED(diRangeDisp->QueryInterface(IID_IHTMLTxtRange, reinterpret_cast<void**>(&diRange))) && diRange)
{
int Result;
unsigned short Res;
diRange->move("word", 1, Result);
diRange->expand("word", Res);
diRange->select();
return true;
}
}
}
}
}
return false;
}
SelectNext(true); // Select the first "word"
// navigate first 200 words
for (int i = 0; i <= 200; i++)
{
SelectNext();
// do spell checking of selected word here...
}

How do I replace a range of characters in Ruby?

With Ruby, how do I replace a range of characters in a string? For instance, given teh string
hellothere
If I want to replace characters at index positions two through five inclusive with "#" to result in a string
he####here
How would I do this?
You could get a string range and replace it by setting the new character multiplied for the last index plus 1 less the first index:
def replace_in_string(str, replace, start, finish)
str[start..finish] = replace * (finish + 1 - start)
str
end
p replace_in_string 'hellothere', '#', 2, 5
# "he####here"

What standard produced hex-encoded characters with an extra "25" at the front?

I'm trying to integrate with ybp.com, a vendor of proprietary software for managing book ordering workflows in large libraries. It keeps feeding me URLs that contain characters encoded with an extra "25" in them. Like this book title:
VOLATILE KNOWING%253a PARENTS%252c TEACHERS%252c AND THE CENSORED STORY OF ACCOUNTABILITY IN AMERICA%2527S PUBLIC SCHOOLS.
The encoded characters in this sample are as follows:
%253a = %3A = a colon
%252c = %2C = a comma
%2527 = %27 = an apostrophe (non-curly)
I need to convert these encodings to a format my internal apps can recognize, and the extra 25 is throwing things off kilter. The final two digits of the hex encoded characters appear to be identical to standard URL encodings, so a brute force method would be to replace "%25" with "%". But I'm leary of doing that because it would be sure to haunt me later when an actual %25 shows up for some reason.
So, what standard is this? Is there an official algorithm for converting values like this to other encodings?
%25 is actually a % character. My guess is that the external website is URLEncoding their output twice accidentally.
If that's the case, it is safe to replace %25 with % (or just URLDecode twice)
The ASCII code 37 (25 in hexadecimal) is %, so the URL encoding of % is %25.
It looks like your data got URL encoded twice: , -> %2C -> %252C
Substituting every %25 for % should not generate any problems, as an actual %25 would get encoded to %25252525.
Create a counter that increments one by one for next two characters, and if you found modulus, you go back, assign the previous counter the '%' char and proceed again. Something like this.
char *str, *newstr; // Fill up with some memory before proceeding below..
....
int k = 0, j = 0;
short modulus = 0;
char first = 0, second = 0;
short proceed = 0;
for(k=0,j=0; k<some_size; j++,k++) {
if(str[k] == '%') {
++k; first = str[k];
++k; second = str[k];
proceed = 1;
} else if(modulus == 1) {
modulus = 0;
--j; first = str[k];
++k; second = str[k];
newstr[j] = '%';
proceed = 1;
} else proceed = 0; // Do not do decoding..
if(proceed == 1) {
if(first == '2' && second == '5') {
newstr[j] = '%';
modulus = 1;
......

String manipulation(ASP.NET MVC)

I have here a code that gets a portion of a record on my database and display it and has a link ("Read More") that renders the viewer to the detailed page of that record..
<% Dim id As Integer = _news.Rows(count).Item("IDnews")%>
<%=_news.Rows(count).Item("newsTitle")%>
<img src='<%= Url.Content("~/NewsPictures/" + _news.Rows(count).Item("newsThumbnail")) %>' alt="" />
<%Dim content As String = _news.Rows(count).Item("newsContent")%>
<%If content.Length > 50 Then%>
<%content = content.Substring(0, 150) & "..."%>
<%End If%>
<%=content%>
<%=Html.ActionLink("Read More", "NewsPublic", "Administration", New With {id}, DBNull.Value)%>
It displays something like:
We assure you that the U... Read More
I would like that the last word be completed before it is cut, or maybe 3 sentences should be displayed before it is cut. The last word in the above sample should be 'University'.
you could do something which finds the first space after the 150th character, or if it cant find a space extends to the end. e.g.
<%content = content.Substring(0, (content.IndexOf(" ", 150) < 0 ? content.Length : content.IndexOf(" ", 150))) & "..."%>
If you know there is a space after the 150 character then:
<%content = content.Substring(0, content.IndexOf(" ", 150)) & "..."%>
would be sufficient
content.Substring(0, content.IndexOf(" ", 150))
Replace the line
<%content = content.Substring(0, 150) & "..."%>
with
<%content = GetStartOfString(content, 150) %>
Then create a function similar to this in a utilities class or wherever you keep code that you reuse.
public static string GetStartOfString(string s, int length)
{
if (s.Length <= length)
{
return s;
}
if(s.IndexOf(" ",length) > 0)
return s.Substring(0, s.IndexOf(" ",length));
return s.substring(0,length);
}
This way you have all the code in one place rather than spread across multiple places. (DRY)
Also you could globalize the length in this method and have it work site wide with just a small change.
An alternative solution would be to have 2 fields in your database. One for the main Content and one for a Headline. The Headline provides a summary of the main Content and be limited to 150 characters. This would avoid any spaghetti code in your View and your content would be better described.

Resources