Разбор пользовательского ввода в поле edittext даты типа и проверка правильности формата даты

Я работаю над приложением для Android и обрабатываю пользовательский ввод из поля edittext. Я хочу проверить, ввел ли пользователь правильный формат даты; однако по причинам, которые я не понимаю, мне нужно преобразовать тип даты типа edittext в строку, а затем преобразовать его обратно в число с плавающей запятой, чтобы проверить регулярное выражение, и это не работает правильно.

Файл editactivity.xml:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:weightSum="1">

    <EditText
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:id="@+id/et_normal_text"
        android:hint="Enter the title of your selfie"
        android:inputType="text"
        android:textStyle="bold"/>

    <EditText
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:id="@+id/et_name"
        android:hint="Enter the title of your selfie"
        android:inputType="text"
        android:textStyle="bold"/>

    <EditText
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:id="@+id/name"
        android:hint="Enter the title of your selfie"
        android:inputType="text"
        android:textStyle="bold"/>

    <EditText
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:id="@+id/et_location"
        android:hint="Enter the title of your selfie"
        android:inputType="text"
        android:textStyle="bold"/>

    <EditText
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:id="@+id/et_email_address"
        android:textStyle="bold"
        android:inputType="textEmailAddress"
        android:hint="Enter Email Address"/>

    <EditText
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:id="@+id/ed_date"
        android:hint="Enter Date"
        android:inputType="date"
        android:textStyle="bold"/>

    <EditText
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:id="@+id/location"
        android:hint="Enter Location"
        android:inputType="textAutoComplete"
        android:textStyle="bold"/>

    <Button
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="Submit"
        android:id="@+id/btn_submit" />

    <ImageView
        android:id="@+id/imageView1"
        android:layout_width="match_parent"
        android:layout_height="106dp"
        android:padding="1dp"
        android:layout_weight="0.98"></ImageView>

    <Button
        android:id="@+id/btnCapture"
        android:layout_width="135dp"
        android:layout_height="wrap_content"
        android:text="Take picture" />

    <Button
        android:id="@+id/save"
        android:layout_width="135dp"
        android:layout_height="wrap_content"
        android:text="Save" />

    <Button
        android:id="@+id/cancel"
        android:layout_width="135dp"
        android:layout_height="wrap_content"
        android:onClick="onClick"
        android:text="Cancel" />

    <Button
        android:id="@+id/image"
        android:layout_width="135dp"
        android:layout_height="wrap_content"
        android:text="See Image" />

</LinearLayout>

EditActivity:

package gmbh.packagename.myselfieme;
import android.app.Activity;
import android.content.ContentValues;
import android.content.Intent;
import android.database.sqlite.SQLiteDatabase;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Rect;
import android.icu.util.Calendar;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.text.Editable;
import android.text.InputType;
import android.text.TextWatcher;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.Toast;
import com.google.android.gms.maps.model.BitmapDescriptorFactory;
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.MarkerOptions;
import static gmbh.packagename.myselfieme.R.drawable.marker;
import static gmbh.packagename.myselfieme.R.id.date;
import static gmbh.packagename.myselfieme.R.id.time;
import static gmbh.packagename.myselfieme.R.string.snippet;


public class EditActivity extends Activity {


    public static int count = 0;
    static final int REQUEST_TAKE_PHOTO = 1;
    private static final String KEY_MARKER_ID = "id";
    private static final String KEY_MARKER_TITLE = "title";
    private static final String KEY_MARKER_DATE = "date";
    private static final String KEY_MARKER_LOC = "location";
    private static final String KEY_MARKER_LAT = "latlng";
    private static final String KEY_MARKER_NAME = "name";
    private static final String KEY_MARKER_PIC = "picture";
    private static final int CAMERA_REQUEST = 1888;

    private EditText etNormalText;
    private EditText etName;
    private EditText etLocation;
    private EditText etEmailAddrss;
    private EditText etDate;
    private Button btnSubmit;
    private ImageView imageView;
    Bitmap photo;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.editactivity);
        PostsDatabaseHelper helper = PostsDatabaseHelper.getInstance(this);
        helper.getReadableDatabase();
        registerViews();
        this.imageView = (ImageView) this.findViewById(R.id.imageView1);
        Button photoButton = (Button) this.findViewById(R.id.btnCapture);
        photoButton.setOnClickListener(new View.OnClickListener() {

            @Override
            public void onClick(View v) {
                Intent cameraIntent = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
                startActivityForResult(cameraIntent, CAMERA_REQUEST);
            }
        });
    }
    private void registerViews() {
        etNormalText = (EditText) findViewById(R.id.et_normal_text);
        etName = (EditText) findViewById(R.id.et_name);
        etLocation = (EditText) findViewById(R.id.et_location);
        // TextWatcher would let us check validation error on the fly
        etNormalText.addTextChangedListener(new TextWatcher() {
            public void afterTextChanged(Editable s) {
                Validation.hasText(etNormalText);
            }
            public void beforeTextChanged(CharSequence s, int start, int count, int after){}
            public void onTextChanged(CharSequence s, int start, int before, int count){}
        });
        etName.addTextChangedListener(new TextWatcher() {
            public void afterTextChanged(Editable s) {
                Validation.hasText(etName);
            }
            public void beforeTextChanged(CharSequence s, int start, int count, int after){}
            public void onTextChanged(CharSequence s, int start, int before, int count){}
        });
        etLocation.addTextChangedListener(new TextWatcher() {
            public void afterTextChanged(Editable s) {
                Validation.hasText(etLocation);
            }
            public void beforeTextChanged(CharSequence s, int start, int count, int after){}
            public void onTextChanged(CharSequence s, int start, int before, int count){}
        });
        etEmailAddrss = (EditText) findViewById(R.id.et_email_address);
        etEmailAddrss.addTextChangedListener(new TextWatcher() {
            // after every change has been made to this editText, we would like to check validity
            public void afterTextChanged(Editable s) {
                Validation.isEmailAddress(etEmailAddrss, true);
            }
            public void beforeTextChanged(CharSequence s, int start, int count, int after){}
            public void onTextChanged(CharSequence s, int start, int before, int count){}
        });

        etDate = (EditText) findViewById(R.id.ed_date);
        etDate.addTextChangedListener(new TextWatcher() {
            public void afterTextChanged(Editable s) {
                Validation.isDate(etDate, false);
            }
            public void beforeTextChanged(CharSequence s, int start, int count, int after){}
            public void onTextChanged(CharSequence s, int start, int before, int count){}
        });

        btnSubmit = (Button) findViewById(R.id.btn_submit);
        btnSubmit.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {

                Log.w("EditActivity", "clicking on btn_submit");
                /*
                Validation class will check the error and display the error on respective fields
                but it won't resist the form submission, so we need to check again before submit
                 */
                if ( checkValidation () )
                    submitForm();
                else
                    Toast.makeText(EditActivity.this, "Form contains error", Toast.LENGTH_LONG).show();
            }
        });

        final LatLng latlng = getIntent().getParcelableExtra("location");
        final EditText title = (EditText) findViewById(R.id.title);
        final EditText date = (EditText) findViewById(R.id.ed_date);
        final EditText location = (EditText) findViewById(R.id.location);
        final EditText name = (EditText) findViewById(R.id.name);
        Button button = (Button) findViewById(R.id.save);
        Button cancelbutton = (Button) findViewById(R.id.cancel);
        Button imagebutton = (Button) findViewById(R.id.image);


        imagebutton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Intent myIntent = new Intent(EditActivity.this, ImageActivity.class);
                myIntent.putExtra("marker", marker);
                myIntent.putExtra("BitmapImage", photo);
                EditActivity.this.startActivity(myIntent);
                setResult(Activity.RESULT_OK, myIntent);
            }
        });

        date.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if(date.getText().length()<1){
                    // Display toast
                    Toast.makeText(getApplicationContext(), "Please enter something !",Toast.LENGTH_LONG).show();
                }

            }

        });

        date.addTextChangedListener(new TextWatcher(){

            @Override
            public void beforeTextChanged(CharSequence s, int start, int count,
                                          int after) {
                if(date.getText().length()<1){
                    // Display toast
                    Toast.makeText(getApplicationContext(), "Please enter something !",Toast.LENGTH_LONG).show();
                }
            }

            @Override
            public void onTextChanged(CharSequence s, int start, int before,
                                      int count) {

            }
            @Override
            public void afterTextChanged(Editable s) {
                // TODO Auto-generated method stub
                //String ss = date.getText().toString();
                int o = 0;

                //String regEx ="^(0[1-9]|1[012])[- /.](0[1-9]|[12][0-9]|3[01])[- /.](19|20)\\d{2}$";

                /*
                                if ((ss.charAt(2) == '/') && (ss.charAt(4) == '/')) {

                                }*/
                int ss = date.getInputType();

                if (ss == (InputType.TYPE_CLASS_DATETIME | InputType.TYPE_DATETIME_VARIATION_DATE))
                {
                    int dateInput = Integer.parseInt(date.getText().toString());

                    //(0?[1-9]|[12][0-9]|3[01])/(0?[1-9]|1[012])/((19|20)\\d\\d)

                    Toast.makeText(EditActivity.this, "Format Is right", Toast.LENGTH_LONG).show();
                }

               /* if (ss.matches("\\d{4}-\\d{2}-\\d{2}")) {
                    Toast.makeText(EditActivity.this, "Format Is right", Toast.LENGTH_LONG).show();
                }*/
                /*if(date.getText().length()<4){
                    // Display toast
                    Toast.makeText(getApplicationContext(), "Please enter something !",Toast.LENGTH_LONG).show();
                }*/
                else {
                    date.setTextColor(Color.RED);
                    date.setText("Invalid Format");
                }
                //ss = "";
            }
        });


        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(final View view) {
                Bitmap resized = Bitmap.createScaledBitmap(photo, (int) (photo.getWidth() * 0.5), (int) (photo.getHeight() * 0.5), true);

                //Bitmap.Config conf = Bitmap.Config.ARGB_8888;
                //Bitmap bmp = Bitmap.createBitmap(150, 150, conf);
                Canvas canvas1 = new Canvas();
                Rect rectangle = new Rect(0,0,100,100);
                canvas1.drawBitmap(resized, new Rect(0,0,100,100), rectangle, null);
                resized = addBorderToBitmap(resized, 10, Color.WHITE);
                // Add a border around the bitmap as shadow
                resized = addBorderToBitmap(resized, 3, Color.LTGRAY);
                MarkerOptions marker = new MarkerOptions().position(latlng)
                        .icon(BitmapDescriptorFactory.fromBitmap(resized))
                        .draggable(true);
                if (title.getText() != null) {

                    marker.title(title.getText().toString());
                }
                if( date.getText().toString().length() == 0 )
                    date.setError( "date is required!" );
                marker.snippet(date.getText().toString());
                if (name.getText() !=null) {
                    marker.snippet(name.getText().toString());
                }
                if (location.getText() !=null) {
                    marker.snippet(location.getText().toString());
                }
                Intent resultIntent = new Intent();
                resultIntent.putExtra("marker", marker);
                resultIntent.putExtra("BitmapImage", photo); // passing the bitmap to the next activity . and retrieve it to the next activity
                setResult(Activity.RESULT_OK, resultIntent);
                finish();
            }

        });}

    public static Bitmap overlay(Bitmap bmp, Bitmap resized) {
        Bitmap bmOverlay = Bitmap.createBitmap(bmp.getWidth(), bmp.getHeight(), bmp.getConfig());
        Canvas canvas = new Canvas(bmOverlay);
        canvas.drawBitmap(bmp, new Matrix(), null);
        canvas.drawBitmap(resized, 0, 0, null);
        return bmOverlay;
    }

    private void submitForm() {
        // Submit your form here. your form is valid
        Toast.makeText(this, "Submitting form...", Toast.LENGTH_LONG).show();
        Log.w("EditActivity", "submitForm");
    }

    private boolean checkValidation() {
        Log.w("EditActivity", "checkValidation");
        boolean ret = true;

        if (!Validation.hasText(etNormalText)) ret = false;
        if (!Validation.isEmailAddress(etEmailAddrss, true)) ret = false;
        if (!Validation.isDate(etDate, false)) ret = false;
        return ret;

    }


    public void onClick(View v) {
        // TODO:
        // Launch Activity Two
        // Hint: use Context's startActivity() method
        // Create an intent stating which Activity you would like to start
        Intent myIntent = new Intent(EditActivity.this, MapsActivity.class);

        // Launch the Activity using the intent
        EditActivity.this.startActivity(myIntent);
    }

    protected Bitmap addBorderToBitmap(Bitmap resized, int borderWidth, int borderColor) {
        // Initialize a new Bitmap to make it bordered bitmap
        Bitmap dstBitmap = Bitmap.createBitmap(
                resized.getWidth() + borderWidth * 2, // Width
                resized.getHeight() + borderWidth * 2, // Height
                Bitmap.Config.ARGB_8888 // Config
        );

        /*
            Canvas
                The Canvas class holds the "draw" calls. To draw something, you need 4 basic
                components: A Bitmap to hold the pixels, a Canvas to host the draw calls (writing
                into the bitmap), a drawing primitive (e.g. Rect, Path, text, Bitmap), and a paint
                (to describe the colors and styles for the drawing).
        */
        // Initialize a new Canvas instance
        Canvas canvas = new Canvas(dstBitmap);

        // Initialize a new Paint instance to draw border
        Paint paint = new Paint();
        paint.setColor(borderColor);
        paint.setStyle(Paint.Style.STROKE);
        paint.setStrokeWidth(borderWidth);
        paint.setAntiAlias(true);
        Rect rect = new Rect(
                borderWidth / 2,
                borderWidth / 2,
                canvas.getWidth() - borderWidth / 2,
                canvas.getHeight() - borderWidth / 2
        );

          // Draw a rectangle as a border/shadow on canvas
        canvas.drawRect(rect, paint);

        // Draw source bitmap to canvas
        canvas.drawBitmap(resized, borderWidth, borderWidth, null);
            resized.recycle();
            // Return the bordered circular bitmap
            return dstBitmap;
   }

    public void onActivityResult(int requestCode, int resultCode, Intent data) {
        if (requestCode == CAMERA_REQUEST && resultCode == Activity.RESULT_OK) {
            photo = (Bitmap) data.getExtras().get("data");
            this.imageView.setImageBitmap(photo);
        }
    }

}

Проблема в этом фрагменте кода здесь:

@Override
            public void afterTextChanged(Editable s) {
                // TODO Auto-generated method stub
                //String ss = date.getText().toString();
                int o = 0;

                //String regEx ="^(0[1-9]|1[012])[- /.](0[1-9]|[12][0-9]|3[01])[- /.](19|20)\\d{2}$";

                /*
                                if ((ss.charAt(2) == '/') && (ss.charAt(4) == '/')) {

                                }*/
                int ss = date.getInputType();

                if (ss == (InputType.TYPE_CLASS_DATETIME | InputType.TYPE_DATETIME_VARIATION_DATE))
                {
                    int dateInput = Integer.parseInt(date.getText().toString());

                    //(0?[1-9]|[12][0-9]|3[01])/(0?[1-9]|1[012])/((19|20)\\d\\d)

                    Toast.makeText(EditActivity.this, "Format Is right", Toast.LENGTH_LONG).show();
                }

               /* if (ss.matches("\\d{4}-\\d{2}-\\d{2}")) {
                    Toast.makeText(EditActivity.this, "Format Is right", Toast.LENGTH_LONG).show();
                }*/
                /*if(date.getText().length()<4){
                    // Display toast
                    Toast.makeText(getApplicationContext(), "Please enter something !",Toast.LENGTH_LONG).show();
                }*/
                else {
                    date.setTextColor(Color.RED);
                    date.setText("Invalid Format");
                }
                //ss = "";
            }
        });

Это validation.java:

package gmbh.package.myselfieme;

import android.widget.EditText;
import java.util.regex.Pattern;

public class Validation {

    // Regular Expression
    // you can change the expression based on your need
    private static final String EMAIL_REGEX = "^[_A-Za-z0-9-\\+]+(\\.[_A-Za-z0-9-]+)*@[A-Za-z0-9-]+(\\.[A-Za-z0-9]+)*(\\.[A-Za-z]{2,})$";
    private static final String DATE_REGEX = "^\\d{4}-\\d{2}-\\d{2}$";

    // Error Messages
    private static final String REQUIRED_MSG = "required";
    private static final String EMAIL_MSG = "invalid email";
    private static final String DATE_MSG = "###-#######";

    // call this method when you need to check email validation
    public static boolean isEmailAddress(EditText editText, boolean required) {
        return isValid(editText, EMAIL_REGEX, EMAIL_MSG, required);
    }

    // call this method when you need to check phone number validation
    public static boolean isDate(EditText editText, boolean required) {
        return isValid(editText, DATE_REGEX, DATE_MSG, required);
    }

    // return true if the input field is valid, based on the parameter passed
    public static boolean isValid(EditText editText, String regex, String errMsg, boolean required) {

        String text = editText.getText().toString().trim();
        // clearing the error, if it was previously set by some other values
        editText.setError(null);

        // text required and editText is blank, so return false
        if ( required && !hasText(editText) ) return false;

        // pattern doesn't match so returning false
        if (required && !Pattern.matches(regex, text)) {
            editText.setError(errMsg);
            return false;
        };

        return true;
    }

    // check the input field has any text or not
    // return true if it contains text otherwise false
    public static boolean hasText(EditText editText) {

        String text = editText.getText().toString().trim();
        editText.setError(null);

        // length 0 means there is no text
        if (text.length() == 0) {
            editText.setError(REQUIRED_MSG);
            return false;
        }

        return true;
    }
}

Это сообщение об ошибке:

  Process: gmbh.packagename.myselfieme, PID: 17795
                                                                            java.lang.NumberFormatException: Invalid int: "2505250525"
                                                                                at java.lang.Integer.invalidInt(Integer.java:138)
                                                                                at java.lang.Integer.parse(Integer.java:413)
                                                                                at java.lang.Integer.parseInt(Integer.java:367)
                                                                                at java.lang.Integer.parseInt(Integer.java:334)
                                                                                at gmbh.packagename.myselfieme.EditActivity$10.afterTextChanged(EditActivity.java:203)

На самом деле, зачем мне нужно читать ввод в виде даты ввода, приводить его к целому числу и проверять, имеет ли это целочисленное значение правильный формат? Неужели нет другого, лучшего способа? Я просто хочу проверить, что пользователи не вводят более 6 цифр и что эти цифры имеют правильный формат.

Любые подсказки или помощь будут оценены, спасибо!


person user8623502    schedule 19.11.2017    source источник
comment
Пожалуйста, резюмируйте свой вопрос, если это возможно. Я не могу понять, что вы спрашиваете. На мой взгляд, вам, возможно, следует использовать средство выбора даты, которое сводит к минимуму (хотя и не устраняет полностью) вероятность неправильного ввода данных пользователем.   -  person Tim Biegeleisen    schedule 19.11.2017
comment
@TimBiegeleisen: Хорошо, спасибо за ваш комментарий - я постараюсь это уточнить. По сути, я хочу проверить ввод пользователя как шестизначное число, как правильную дату, и большинство предложений по переполнению стека заключались в том, чтобы сделать это с помощью прослушивателя текста.   -  person user8623502    schedule 19.11.2017
comment
Правильно ли я понимаю, что пользовательский ввод должен соответствовать шаблону регулярного выражения DATE_REGEX = "^\\d{4}-\\d{2}-\\d{2}$"?   -  person Ole V.V.    schedule 19.11.2017


Ответы (2)


Я просто хочу проверить, что пользователи не вводят более 6 цифр и что эти цифры имеют правильный формат.

Допустим, требуется формат дд-мм-гг.

Используйте регулярное выражение - \d{2}-\d{2}-\d{2}

Например,

if (inputSTR.matches("\\d{2}-\\d{2}-\\d{2}")) {
    // input matches to required pattern
} else {
    // Show error msg
}
person Paresh P.    schedule 19.11.2017
comment
большое спасибо - это именно то, что я хотел сделать с этим: if (ss.matches(\\d{4}-\\d{2}-\\d{2})) { Toast.makeText(EditActivity .this, Формат правильный, Toast.LENGTH_LONG).show(); } - однако совпадения методов не могут быть разрешены, что приводит к ошибке Не удается разрешить совпадения методов (java.lang.string). Итак, в этом моя проблема: номер даты преобразуется в строку и обратно, чтобы сделать ее разборчивой, а затем метод не может быть применен, потому что это не строка. Я действительно застрял здесь, помощь была бы здорово! - person user8623502; 19.11.2017
comment
Да, я бы с удовольствием, но у меня все еще есть эта проблема ... Я в основном застрял в вышеупомянутой части проблемы. - person user8623502; 19.11.2017
comment
Я не понимаю, зачем вы вообще разбираете на Integer? Просто получите ввод от EditText и сопоставьте с регулярным выражением. Это все. - person Paresh P.; 19.11.2017

Во-первых, Комментарий Тима Бигелейзена о том, что вам следует использовать средство выбора даты, а не EditText, вероятно, заслуживает внимания.

В любом случае, если вы получаете дату в виде строки, рекомендуемый способ ее проверки — попытаться преобразовать ее в дату и посмотреть, удастся ли вам это сделать, а не с помощью регулярного выражения. И вам, конечно же, не следует пытаться анализировать его как целое число, это обречено на неудачу. Мой код будет выглядеть примерно так:

    String ss = date.getText().toString();
    if (ss.isEmpty()) {
        // tell the user to enter something
    } else {
        try {
            LocalDate.parse(ss);
            // tell the user the format is right
        } catch (DateTimeParseException dtpe) {
            // tell the user that this is not a valid date
        }
    }

Я предполагаю, что ваша дата должна быть в формате гггг-мм-дд. Это формат анализа по умолчанию для LocalDate, так что это довольно просто, если вы знаете об исключениях и конструкциях try/catch. Если вам нужен другой формат, вам нужно будет указать его через DateTimeFormatter.

Преимущество перед подходом с регулярными выражениями заключается в том, что он дает вам гораздо лучшую проверку. ^\\d{4}-\\d{2}-\\d{2}$ примет 2017-29-11 и 2017-11-92 как даты, где подход к синтаксическому анализу поймает, если месяц не от 1 до 12 или день месяца не находится в пределах количества дней в этом месяце.

Теперь вы на этом, если вам нужно сохранить свою дату (вероятно, поскольку вы попросили пользователя ввести ее), сохраните ее как объект LocalDate, а не строку. Это подготовит ваше приложение к выполнению всех видов операций на дату. Всякий раз, когда вам нужна строка, просто используйте LocalDate.toString(). Или используйте DateTimeFormatter, если вам нужна строка, например, «Воскресенье, 19 ноября 2017 года» или даже на немецком или другом языке.

Я использую java.time, современный API даты и времени Java, также известный как JSR-310. К сожалению, этого пока нет на большинстве Android-устройств. Решение — ThreeTenABP, бэкпорт JSR-310 на Android. Я призываю вас получить это и начать кодирование.

person Ole V.V.    schedule 19.11.2017