simplified regex for modifying a string in ruby - ruby

Here is my original string:
"Chassis ID TLV\n\tMAC: 00:xx:xx:xx:xx:xx\nPort ID TLV\n\tIfname: Ethernet1/3\nTime to Live TLV\n\t120"
and i want the string to be formatted as :
"Chassis ID TLV;00:xx:xx:xx:xx:xx\nPort ID TLV;Ethernet1/3\nTime to Live TLV;120"
so i used following ruby string functions to do it:
y = x.gsub(/\t[a-zA-Z\d]+:/,"\t")
y = y.gsub(/\t /,"\t")
y = y.gsub("\n\t",";")
so i am looking for a one liner to do the above. since i am not used to regex, i tried doing it sequentially. i am messing it up when i try to do all of them together.

Replace the following construct
[\n\r]\t(?:\w+: )?
with ;, see a demo on regex101.com.

I'd tackle it as a few smaller steps:
input = "Chassis ID TLV\n\tMAC: 00:xx:xx:xx:xx:xx\nPort ID TLV\n\tIfname: Ethernet1/3\nTime to Live TLV\n\t120"
input.split(/\n\t?/).map { |s| s.sub(/\A[^:]+\:\s*/, '') }.join(';')
# => "Chassis ID TLV;00:xx:xx:xx:xx:xx;Port ID TLV;Ethernet1/3;Time to Live TLV;120"
That way you have control over each element instead of being entirely dependent on the regular expression to do it as one shot.

Related

Is it possible to sort with gsub (anonymous function) like ruby in Scala?

Im new in Scala. I need to know if is possible do something like this in Scala:
input2.lines.sort_by { |l| l.gsub(/.*?\+(.*?)\+(.*)\n/,"\\2\n").to_i }
Please help
It looks like you're trying to sort strings by a sub-section within each string. To do that you first need a regex with a capture group to select the region you're interested in.
val re = ".*\\+.*\\+(\\d+)".r
Now you can extract and modify what was captured and use the result as the sorting rule.
lines.sortBy{case re(n) => n.toInt}

How can I compare strings case sensitive in xforms:select1 ref attribute?

I have to provide the ref attribute value in an xf:select1. I need to select names of properties only if they are present in the supportedProperties instance which can be done with the following:
<xf:select1
ref="
instance('properties')/property[
name = instance('supportedProperties')/property/name
]/name">
However, the problem is that supportedProperties can contain names which are in capital letters. Assuming we cannot change the instance, is there a way we can do a case sensitive comparison?
Tried to use the lower-case() XPath function as follows but it didn't work:
<xf:select1
ref="
instance('properties')/property[
name = instance('supportedProperties')/property/name
]/lower-case(name)">
Assuming you are using XPath 2, you can write:
<xf:select1
ref="
instance('properties')/property[
name = instance('supportedProperties')/property/name/lower-case(.)
]/name">
What this does is that the lower-case(.) function applies to all elements in the sequence returned by instance('supportedProperties')/property/name.
You can also write it:
<xf:select1
ref="
instance('properties')/property[
name = (
for $name in instance('supportedProperties')/property/name
return lower-case($name)
)
]/name">

Parse a string with multiple XML-like tags using Ruby

I have a string which looks like the following:
string = " <SET-TOPIC>INITIATE</SET-TOPIC>
<SETPROFILE>
<PROFILE-KEY>predicates_live</PROFILE-KEY>
<PROFILE-VALUE>yes</PROFILE-VALUE>
</SETPROFILE>
<think>
<set><name>first_time_initiate</name>yes</set>
</think>
<SETPROFILE>
<PROFILE-KEY>first_time_initiate</PROFILE-KEY>
<PROFILE-VALUE>YES</PROFILE-VALUE>
</SETPROFILE>"
My objective is to be able to read out each top level that is in caps with the parse. I use a case statement to evaluate what is the top level key, such as <SETPROFILE> but there can be lots of different values, and then run a method that does different things with the contnts of the tag.
What this means is I need to be able to know very easily:
top_level_keys = ['SET-TOPIC', 'SET-PROFILE', 'SET-PROFILE']
when I pass in the key know the full value
parsed[0].value = {:PROFILE-KEY => predicates_live, :PROFILE-VALUE => yes}
parsed[0].key = ['SET-TOPIC']
I currently parse the whole string as follows:
doc = Nokogiri::XML::DocumentFragment.parse(string)
parsed = doc.search('*').each_with_object({}){ |n, h|
h[n.name] = n.text
}
As a result, I only parse and know of the second tag. The values from the first tag do not show up in the parsed variable.
I have control over what the tags are, if that helps.
But I need to be able to parse and know the contents of both tag as a result of the parse because I need to apply a method for each instance of the node.
Note: the string also contains just regular text, both before, in between, and after the XML-like tags.
It depends on what you are going to achieve. The problem is that you are overriding hash keys by new values. The easiest way to collect values is to store them in array:
parsed = doc.search('*').each_with_object({}) do |n, h|
# h[n.name] = n.text :: removed because it overrides values
(h[n.name] ||= []) << n.text
end

Selenium Webdriver + Ruby regex: Can I use regex with find_element?

I am trying to click an element that changes per each order like so
edit_div_123
edit_div_124
edit_div_xxx
xxx = any three numbers
I have tried using regex like so:
#driver.find_element(:css, "#edit_order_#{\d*} > div.submit > button[name=\"commit\"]").click
#driver.find_element(:xpath, "//*[(#id = "edit_order_#{\d*}")]//button").click
Is this possible? Any other ways of doing this?
You cannot use Regexp, like the other answers have indicated.
Instead, you can use a nifty CSS Selector trick:
#driver.find_element(:css, "[id^=\"edit_order_\"] > div.submit > button[name=\"commit\"]").click
Using:
^= indicates to find the element with the value beginning with your criteria.
*= says the criteria should be found anywhere within the element's value
$= indicates to find the element with with your criteria at the end of the value.
~= allows you to find the element based on a single criteria when the actual value has multiple space-seperated list of values.
Take a look at http://net.tutsplus.com/tutorials/html-css-techniques/the-30-css-selectors-you-must-memorize/ for some more info on other neat CSS tricks you should add to your utility belt!
You have no provided any html fragment that you are working on. Hence my answer is just based on the limited inputs provided your question.
I don't think WebDriver APIs support regex for locating elements. However, you can achieve what you want using just plain XPath as follows:
//*[starts-with(#id, 'edit_div_')]//button
Explanation: Above xpath will try to search all <button> nodes present under all elements whose id attribute starts with string edit_div_
In short, you can use starts-with() xpath function in order to match element with id format as edit_div_ followed by any number of characters
No, you can not.
But you should do something like this:
function hasClass(element, className) {
var re = new RegExp('(?:^|\\s+)' + className + '(?:\\s+|$)');
return re.test(element.className);
}
This worked for me
#driver.find_element(:xpath, "//a[contains(#href, 'person')]").click

Is it possible to exclude some of the string used to match from Ruby regexp data?

I have a bunch of strings that look, for example, like this:
<option value="Spain">Spain</option>
And I want to extract the name of the country from inside.
The easiest way I could think of to do this in Ruby was to use a regular expression of this form:
country = line.match(/>(.+)</)
However, this returns >Spain<. So I did this:
line.match(/>(.+)</).to_s.gsub!(/<|>/,"")
Works well enough, but I'd be surprised if there's not a more elegant way to do this? It seems like using a regular expression to declare how to find the thing you want, without actually wanting the enclosing strings that were used to match it to be part of the data that gets returned.
Is there a conventional approach to this problem?
The right way to deal with that string is to use an HTML parser, for example:
country = Nokogiri::HTML('<option value="Spain">Spain</option>').at('option').text
And if you have several such strings, paste them together and use search:
html = '<option value="Spain">Spain</option><option value="Canada">Canada</option>'
countries = Nokogiri::HTML(html).search('option').map(&:text)
# ["Spain", "Canada"]
But if you must use a regex, then:
country = '<option value="Spain">Spain</option>'.match('>([^<]+)<')[1]
Keep in mind that match actually returns a MatchData object and MatchData#to_s:
Returns the entire matched string.
But you can access the captured groups using MatchData#[]. And if you don't like counting, you could use a named capture group as well:
country = '<option value="Spain">Spain</option>'.match('>(?<name>[^<]+)<')['name']

Resources