Let's assume we have a multiline string, like
var s:String = "my first line\nmy second line\nmy third line\nand so on!";
What is the best way to get (only) the first line of this string in Haxe? I know I can do something like:
static function getFirstLine(s:String):String {
var t:String = s.split("\n")[0];
if(t.charAt(t.length - 1) == "\r") {
t = t.substring(0, t.length - 1);
}
return t;
}
However I'm wondering if there is any easier (predefined) method for this ...
Caveat that #Gama11's answer works well and is more elegant than this.
If your string is long, split will iterate over the whole thing and allocate an array containing every line in your string, both of which are unnecessary here. Another option would be indexOf:
static function getFirstLine(s:String):String {
var i = s.indexOf("\n");
if (i == -1) return s;
if (i > 0 && s.charAt(i - 1) == "\r") --i;
return s.substr(0, i);
}
There's no built-in utility in the standard library for this that I know of, but you make it a bit more elegant and avoid the substring() handling for \r by splitting on a regex:
static function getFirstLine(s:String):String {
return ~/\r?\n/.split(s)[0];
}
The regex \r?\n optionally matches a carriage return followed by a line feed character.
Related
So I have a question where I am checking if a string has every letter of the alphabet in it. I was able to check if there is alphabet in the string, but I'm not sure how to check if there is EVERY alphabet in said string. Here's the code
fun isPangram (pangram: Array<String>) : String {
var panString : String
var outcome = ""
for (i in pangram.indices){
panString = pangram[i]
if (panString.matches(".^*[a-z].*".toRegex())){
outcome = outcome.plus('1')
}
else {outcome = outcome.plus('0')}
}
return outcome
}
Any ideas are welcomed Thanks.
I think it would be easier to check if all members of the alphabet range are in each string than to use Regex:
fun isPangram(pangram: Array<String>): String =
pangram.joinToString("") { inputString ->
when {
('a'..'z').all { it in inputString.lowercase() } -> "1"
else -> "0"
}
}
Hi this is how you can make with regular expression
Kotlin Syntax
fun isStrinfContainsAllAlphabeta( input: String) {
return input.lowercase()
.replace("[^a-z]".toRegex(), "")
.replace("(.)(?=.*\\1)".toRegex(), "")
.length == 26;
}
In java:
public static boolean isStrinfContainsAllAlphabeta(String input) {
return input.toLowerCase()
.replace("[^a-z]", "")
.replace("(.)(?=.*\\1)", "")
.length() == 26;
}
the function takes only one string. The first "replaceAll" removes all the non-alphabet characters, The second one removes the duplicated character, then you check how many characters remained.
Just to bounce off Tenfour04's solution, if you write two functions (one for the pangram check, one for processing the array) I feel like you can make it a little more readable, since they're really two separate tasks. (This is partly an excuse to show you some Kotlin tricks!)
val String.isPangram get() = ('a'..'z').all { this.contains(it, ignoreCase = true) }
fun checkPangrams(strings: Array<String>) =
strings.joinToString("") { if (it.isPangram) "1" else "0" }
You could use an extension function instead of an extension property (so it.isPangram()), or just a plain function with a parameter (isPangram(it)), but you can write stuff that almost reads like English, if you want!
if my string is lets say "Alfa1234Beta"
how can I convert all the number in to "_"
for example "Alfa1234Beta"
will be "Alfa____Beta"
Going with the Regex approach pointed out by others is possibly OK for your scenario. Mind you however, that Regex sometimes tend to be overused. A hand rolled approach could be like this:
static string ReplaceDigits(string str)
{
StringBuilder sb = null;
for (int i = 0; i < str.Length; i++)
{
if (Char.IsDigit(str[i]))
{
if (sb == null)
{
// Seen a digit, allocate StringBuilder, copy non-digits we might have skipped over so far.
sb = new StringBuilder();
if (i > 0)
{
sb.Append(str, 0, i);
}
}
// Replace current character (a digit)
sb.Append('_');
}
else
{
if (sb != null)
{
// Seen some digits (being replaced) already. Collect non-digits as well.
sb.Append(str[i]);
}
}
}
if (sb != null)
{
return sb.ToString();
}
return str;
}
It is more light weight than Regex and only allocates when there is actually something to do (replace). So, go ahead use the Regex version if you like. If you figure out during profiling that is too heavy weight, you can use something like the above. YMMV
You can run for loop on the string and then use the following method to replace numbers with _
if (!System.Text.RegularExpressions.Regex.IsMatch(i, "^[0-9]*$"))
Here variable i is the character in the for loop .
You can use this:
var s = "Alfa1234Beta";
var s2 = System.Text.RegularExpressions.Regex.Replace(s, "[0-9]", "_");
s2 now contains "Alfa____Beta".
Explanation: the regex [0-9] matches any digit from 0 to 9 (inclusive). The Regex.Replace then replaces all matched characters with an "_".
EDIT
And if you want it a bit shorter AND also match non-latin digits, use \d as a regex:
var s = "Alfa1234Beta๓"; // ๓ is "Thai digit three"
var s2 = System.Text.RegularExpressions.Regex.Replace(s, #"\d", "_");
s2 now contains "Alfa____Beta_".
I'm wondering how (and in which way it's best to do it) to split a string with a unknown number of spaces as separator in C++/CLI?
Edit: The problem is that the space number is unknown, so when I try to use the split method like this:
String^ line;
StreamReader^ SCR = gcnew StreamReader("input.txt");
while ((line = SCR->ReadLine()) != nullptr && line != nullptr)
{
if (line->IndexOf(' ') != -1)
for each (String^ SCS in line->Split(nullptr, 2))
{
//Load the lines...
}
}
And this is a example how Input.txt look:
ThisISSomeTxt<space><space><space><tab>PartNumberTwo<space>PartNumber3
When I then try to run the program the first line that is loaded is "ThisISSomeTxt" the second line that is loaded is "" (nothing), the third line that is loaded is also "" (nothing), the fourth line is also "" nothing, the fifth line that is loaded is " PartNumberTwo" and the sixth line is PartNumber3.
I only want ThisISSomeTxt and PartNumberTwo to be loaded :? How can I do this?
Why not just using System::String::Split(..)?
The following code example taken from http://msdn.microsoft.com/en-us/library/b873y76a(v=vs.80).aspx#Y0 , demonstrates how you can tokenize a string with the Split method.
using namespace System;
using namespace System::Collections;
int main()
{
String^ words = "this is a list of words, with: a bit of punctuation.";
array<Char>^chars = {' ',',','->',':'};
array<String^>^split = words->Split( chars );
IEnumerator^ myEnum = split->GetEnumerator();
while ( myEnum->MoveNext() )
{
String^ s = safe_cast<String^>(myEnum->Current);
if ( !s->Trim()->Equals( "" ) )
Console::WriteLine( s );
}
}
I think you can do what you need to do with the String.Split method.
First, I think you're expecting the 'count' parameter to work differently: You're passing in 2, and expecting the first and second results to be returned, and the third result to be thrown out. What it actually return is the first result, and the second & third results concatenated into one string. If all you want is ThisISSomeTxt and PartNumberTwo, you'll want to manually throw away results after the first 2.
As far as I can tell, you don't want any whitespace included in your return strings. If that's the case, I think this is what you want:
String^ line = "ThisISSomeTxt \tPartNumberTwo PartNumber3";
array<String^>^ split = line->Split((array<String^>^)nullptr, StringSplitOptions::RemoveEmptyEntries);
for(int i = 0; i < split->Length && i < 2; i++)
{
Debug::WriteLine("{0}: '{1}'", i, split[i]);
}
Results:
0: 'ThisISSomeTxt'
1: 'PartNumberTwo'
I was using the TrimStart function to do the following:
var example = "Savings:Save 20% on this stuff";
example = example.TrimStart("Savings:".ToCharArray());
I was expecting this to result in example having a value of "Save 20% on this stuff".
However, what I got was "e 20% on this stuff".
After reading the documentation on TrimStart I understand why, but now I'm left wondering if there is a function in .NET that does what I was trying to do in the first place?
Does anyone know of a function so I don't have to create my own and keep track of it?
I don't think such a method exists but you can easily do it using StartsWith and Substring:
s = s.StartsWith(toRemove) ? s.Substring(toRemove.Length) : s;
You can even add it as an extension method:
public static class StringExtension
{
public static string RemoveFromStart(this string s, string toRemove)
{
if (s == null)
{
throw new ArgumentNullException("s");
}
if (toRemove == null)
{
throw new ArgumentNullException("toRemove");
}
if (!s.StartsWith(toRemove))
{
return s;
}
return s.Substring(toRemove.Length);
}
}
No, I don't believe there's anything which does this built into the framework. It's a somewhat unusual requirement, IMO.
Note that you should think carefully about whether you're trying to remove "the first occurrence" or remove the occurrence at the start of the string, if there is one. For example, think what you'd want to do with: "Hello. Savings: Save 20% on this stuff".
You can do that quite easily using a regular expression.
Remove the occurrence on the beginning of the string:
example = Regex.Replace(example, #"^Savings:", "");
Remove the first occurrence in the string:
example = Regex.Replace(example, #"(?<!Savings:.*)Savings:", "");
I'm building a short quiz where the user needs to input the meaning of an acronym.
This means I need to compare a long string (usually a sentence) typed in by the user with an acronym.
I have a feeling I'm not doing it right. For my testing I'm copy-pasting the correct answer to make sure the spelling is correct however I keep getting the feedback that the answer is incorrect.
My question is, am I comparing correctly?
Here's my code:
var arrQuestions:Array = [["LOL","Laughing Out Loud"], ["OMG", "Oh My God"], ["BTW", "By The Way"]];
var i:Number=0;
function setup():void {
quiztext_txt.text = arrQuestions[i][0];
trace(quiztext_txt.text);
trace(arrQuestions[i][1]);
check_btn.addEventListener(MouseEvent.CLICK, clickHandler);
}//End of Setup()
setup();
function clickHandler(event:MouseEvent):void {
var givenString:String;
var inputString:String;
inputString = userinput_txt.text;
givenString = arrQuestions[i][1];
if (inputString == givenString) {
feedback_txt.text = "Correct!";
} else {
feedback_txt.text = "Wrong!";
}
}
Is there any whitespace before/after the user input? Is the value of i changing in between?
else
{
//what does it trace?
trace("given answer: " + inputString + "\ncorrect answer: " + givenString);
feedback_txt.text = "Wrong!";
}
try clearing the text field in your setup function like so:
function setup():void
{
userinput_txt.text = "";
quiztext_txt.text = arrQuestions[i][0];
trace(quiztext_txt.text);
trace(arrQuestions[i][1]);
check_btn.addEventListener(MouseEvent.CLICK, clickHandler);
}//End of Setup()
For any kind of string matching I would strongly recommend looking into regular expressions (RegExp). In the regular expression written below I am matching each word, then I say [ ]+ which means "at least one or more spaces", then at the end of the expression I use /gi to say that the expression is case insensitive. In the code above if I type the phrase in lowercase its not going to match, a quick fix for this would be to use this if(inputString.toLowerCase() == givenString.toLowerCase()) which would catch this. Heres the regexp example:
// testString could easily equal myTextField.text
var testString:String = "lauGHing OuT loUD";
// you could store each one in an array, as you were before
var regEx:RegExp = /laughing[ ]+out[ ]+loud/gi
trace( regEx.test( testString ) ); //returns true,test() returns a Boolean
Hope this helps.